From c50f59b6b29771ddfa1db2e78f613e88bc8ef700 Mon Sep 17 00:00:00 2001 From: Maksim Strebkov <257byte@gmail.com> Date: Thu, 25 Jul 2024 15:14:18 +0300 Subject: [PATCH 1/3] Init proto21 --- .../Protocols/Handlers/Initiator/Rpc/Rpc.cs | 6 +- .../Proto21/Activation/ProtoActivator.cs | 239 ++++ .../Proto21/Commits/AutostakingCommit.cs | 7 + .../Proto21/Commits/BakerCycleCommit.cs | 7 + .../Proto21/Commits/BakingRightsCommit.cs | 7 + .../Handlers/Proto21/Commits/BigMapCommit.cs | 7 + .../Handlers/Proto21/Commits/BlockCommit.cs | 7 + .../Proto21/Commits/ContractEventCommit.cs | 7 + .../Handlers/Proto21/Commits/CycleCommit.cs | 7 + .../Proto21/Commits/DeactivationCommit.cs | 7 + .../Proto21/Commits/DelegatorCycleCommit.cs | 7 + .../Proto21/Commits/EndorsingRewardCommit.cs | 7 + .../Handlers/Proto21/Commits/InboxCommit.cs | 7 + .../Commits/Operations/ActivationsCommit.cs | 7 + .../Commits/Operations/BallotsCommit.cs | 7 + .../Operations/DalPublishCommitmentCommit.cs | 7 + .../Commits/Operations/DelegationsCommit.cs | 7 + .../Commits/Operations/DoubleBakingCommit.cs | 7 + .../Operations/DoubleEndorsingCommit.cs | 7 + .../Operations/DoublePreendorsingCommit.cs | 7 + .../Commits/Operations/DrainDelegateCommit.cs | 7 + .../Commits/Operations/EndorsementsCommit.cs | 7 + .../Operations/IncreasePaidStorageCommit.cs | 7 + .../Operations/NonceRevelationsCommit.cs | 7 + .../Commits/Operations/OriginationsCommit.cs | 7 + .../Operations/PreendorsementsCommit.cs | 7 + .../Commits/Operations/ProposalsCommit.cs | 7 + .../Operations/RegisterConstantsCommit.cs | 7 + .../Commits/Operations/RevealsCommit.cs | 7 + .../Operations/SetDelegateParametersCommit.cs | 7 + .../Operations/SetDepositsLimitCommit.cs | 7 + .../SmartRollupAddMessagesCommit.cs | 7 + .../Operations/SmartRollupCementCommit.cs | 7 + .../Operations/SmartRollupExecuteCommit.cs | 7 + .../Operations/SmartRollupOriginateCommit.cs | 7 + .../Operations/SmartRollupPublishCommit.cs | 7 + .../SmartRollupRecoverBondCommit.cs | 7 + .../Operations/SmartRollupRefuteCommit.cs | 7 + .../Operations/SmartRollupTimeoutCommit.cs | 7 + .../Commits/Operations/StakingCommit.cs | 7 + .../Commits/Operations/TransactionsCommit.cs | 7 + .../Operations/TransferTicketCommit.cs | 7 + .../Operations/UpdateConsensusKeyCommit.cs | 7 + .../Commits/Operations/VdfRevelationCommit.cs | 7 + .../Proto21/Commits/SlashingCommit.cs | 7 + .../Proto21/Commits/SnapshotBalanceCommit.cs | 7 + .../Proto21/Commits/SoftwareCommit.cs | 7 + .../Proto21/Commits/StakingUpdateCommit.cs | 7 + .../Handlers/Proto21/Commits/StateCommit.cs | 7 + .../Proto21/Commits/StatisticsCommit.cs | 7 + .../Handlers/Proto21/Commits/SubsidyCommit.cs | 7 + .../Handlers/Proto21/Commits/TicketsCommit.cs | 7 + .../Handlers/Proto21/Commits/TokensCommit.cs | 7 + .../Handlers/Proto21/Commits/VotingCommit.cs | 7 + .../Proto21/Diagnostics/Diagnostics.cs | 7 + .../Handlers/Proto21/Proto21Handler.cs | 621 ++++++++++ .../Protocols/Handlers/Proto21/Rpc/Rpc.cs | 9 + .../Handlers/Proto21/Validation/Validator.cs | 1028 +++++++++++++++++ Tzkt.Sync/Protocols/Helpers/Chains.cs | 1 + Tzkt.Sync/Protocols/TezosProtocols.cs | 2 + 60 files changed, 2276 insertions(+), 1 deletion(-) create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Activation/ProtoActivator.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/AutostakingCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BakerCycleCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BakingRightsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BigMapCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BlockCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/ContractEventCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/CycleCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/DeactivationCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/DelegatorCycleCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/EndorsingRewardCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/InboxCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/ActivationsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/BallotsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DalPublishCommitmentCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DelegationsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DoubleBakingCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DoubleEndorsingCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DoublePreendorsingCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DrainDelegateCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/EndorsementsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/IncreasePaidStorageCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/NonceRevelationsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/OriginationsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/PreendorsementsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/ProposalsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/RegisterConstantsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/RevealsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SetDelegateParametersCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SetDepositsLimitCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupAddMessagesCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupCementCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupExecuteCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupOriginateCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupPublishCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupRecoverBondCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupRefuteCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupTimeoutCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/StakingCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/TransactionsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/TransferTicketCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/UpdateConsensusKeyCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/VdfRevelationCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SlashingCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SnapshotBalanceCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SoftwareCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/StakingUpdateCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/StateCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/StatisticsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SubsidyCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/TicketsCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/TokensCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Commits/VotingCommit.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Diagnostics/Diagnostics.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Proto21Handler.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Rpc/Rpc.cs create mode 100644 Tzkt.Sync/Protocols/Handlers/Proto21/Validation/Validator.cs diff --git a/Tzkt.Sync/Protocols/Handlers/Initiator/Rpc/Rpc.cs b/Tzkt.Sync/Protocols/Handlers/Initiator/Rpc/Rpc.cs index 27be6ecf7..f25b3f3b9 100644 --- a/Tzkt.Sync/Protocols/Handlers/Initiator/Rpc/Rpc.cs +++ b/Tzkt.Sync/Protocols/Handlers/Initiator/Rpc/Rpc.cs @@ -1,9 +1,13 @@ -using Tzkt.Sync.Services; +using System.Text.Json; +using Tzkt.Sync.Services; namespace Tzkt.Sync.Protocols.Initiator { sealed class Rpc : Proto1.Rpc { public Rpc(TezosNode node) : base(node) { } + + public override Task GetBlockAsync(int level) + => Node.GetAsync($"chains/main/blocks/{level}"); } } diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Activation/ProtoActivator.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Activation/ProtoActivator.cs new file mode 100644 index 000000000..adc5f08d7 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Activation/ProtoActivator.cs @@ -0,0 +1,239 @@ +using System.Numerics; +using Microsoft.EntityFrameworkCore; +using Npgsql; +using Tzkt.Data.Models; + +namespace Tzkt.Sync.Protocols.Proto21 +{ + partial class ProtoActivator : Proto20.ProtoActivator + { + public ProtoActivator(ProtocolHandler proto) : base(proto) { } + + protected override void UpgradeParameters(Protocol protocol, Protocol prev) + { + if (protocol.TimeBetweenBlocks >= 5) + { + protocol.BlocksPerCycle = protocol.BlocksPerCycle * 5 / 4; + protocol.BlocksPerCommitment = protocol.BlocksPerCommitment * 5 / 4; + protocol.BlocksPerVoting = protocol.BlocksPerVoting * 5 / 4; + protocol.TimeBetweenBlocks = protocol.TimeBetweenBlocks * 4 / 5; + protocol.HardBlockGasLimit = prev.HardBlockGasLimit * 4 / 5; + protocol.SmartRollupCommitmentPeriod = prev.SmartRollupCommitmentPeriod * 5 / 4; + protocol.SmartRollupChallengeWindow = prev.SmartRollupChallengeWindow * 5 / 4; + protocol.SmartRollupTimeoutPeriod = prev.SmartRollupTimeoutPeriod * 5 / 4; + protocol.BlocksPerSnapshot = protocol.BlocksPerCycle; + } + } + + protected override async Task MigrateContext(AppState state) + { + var prevProto = await Cache.Protocols.GetAsync(state.Protocol); + var nextProto = await Cache.Protocols.GetAsync(state.NextProtocol); + + await RemoveDeadRefutationGames(state); + await MigrateSlashing(state, nextProto); + MigrateBakers(state, prevProto, nextProto); + await MigrateVotingPeriods(state, nextProto); + var cycles = await MigrateCycles(state, nextProto); + await MigrateFutureRights(state, nextProto, cycles); + } + + async Task MigrateSlashing(AppState state, Protocol nextProto) + { + foreach (var op in await Db.DoubleBakingOps.Where(x => x.SlashedLevel > state.Level).ToListAsync()) + { + var proto = await Cache.Protocols.FindByLevelAsync(op.AccusedLevel); + op.SlashedLevel = nextProto.GetCycleEnd(proto.GetCycle(op.AccusedLevel) + proto.MaxSlashingPeriod - 1); + } + + foreach (var op in await Db.DoubleEndorsingOps.Where(x => x.SlashedLevel > state.Level).ToListAsync()) + { + var proto = await Cache.Protocols.FindByLevelAsync(op.AccusedLevel); + op.SlashedLevel = nextProto.GetCycleEnd(proto.GetCycle(op.AccusedLevel) + proto.MaxSlashingPeriod - 1); + } + + foreach (var op in await Db.DoublePreendorsingOps.Where(x => x.SlashedLevel > state.Level).ToListAsync()) + { + var proto = await Cache.Protocols.FindByLevelAsync(op.AccusedLevel); + op.SlashedLevel = nextProto.GetCycleEnd(proto.GetCycle(op.AccusedLevel) + proto.MaxSlashingPeriod - 1); + } + } + + void MigrateBakers(AppState state, Protocol prevProto, Protocol nextProto) + { + foreach (var baker in Cache.Accounts.GetDelegates().Where(x => x.DeactivationLevel > state.Level)) + { + Db.TryAttach(baker); + baker.DeactivationLevel = nextProto.GetCycleStart(prevProto.GetCycle(baker.DeactivationLevel)); + } + } + + async Task MigrateVotingPeriods(AppState state, Protocol nextProto) + { + var newPeriod = await Cache.Periods.GetAsync(state.VotingPeriod); + Db.TryAttach(newPeriod); + newPeriod.LastLevel = newPeriod.FirstLevel + nextProto.BlocksPerVoting - 1; + } + + async Task> MigrateCycles(AppState state, Protocol nextProto) + { + var cycles = await Db.Cycles + .Where(x => x.Index >= state.Cycle) + .OrderBy(x => x.Index) + .ToListAsync(); + + var res = await Proto.Rpc.GetExpectedIssuance(state.Level); + + foreach (var cycle in cycles.Where(x => x.Index > state.Cycle)) + { + var issuance = res.EnumerateArray().First(x => x.RequiredInt32("cycle") == cycle.Index); + + cycle.BlockReward = issuance.RequiredInt64("baking_reward_fixed_portion"); + cycle.BlockBonusPerSlot = issuance.RequiredInt64("baking_reward_bonus_per_slot"); + cycle.EndorsementRewardPerSlot = issuance.RequiredInt64("attesting_reward_per_slot"); + cycle.NonceRevelationReward = issuance.RequiredInt64("seed_nonce_revelation_tip"); + cycle.VdfRevelationReward = issuance.RequiredInt64("vdf_revelation_tip"); + + cycle.MaxBlockReward = cycle.BlockReward + cycle.BlockBonusPerSlot * (nextProto.EndorsersPerBlock - nextProto.ConsensusThreshold); + + cycle.FirstLevel = nextProto.GetCycleStart(cycle.Index); + cycle.LastLevel = nextProto.GetCycleEnd(cycle.Index); + } + + return cycles; + } + + async Task MigrateFutureRights(AppState state, Protocol nextProto, List cycles) + { + await Db.Database.ExecuteSqlRawAsync(""" + DELETE FROM "BakingRights" + WHERE "Cycle" > {0} + """, state.Cycle); + + var conn = Db.Database.GetDbConnection() as NpgsqlConnection; + IEnumerable shifted = Enumerable.Empty(); + + foreach (var cycle in cycles) + { + var bakerCycles = await Cache.BakerCycles.GetAsync(cycle.Index); + var sampler = GetSampler(bakerCycles.Values + .Where(x => x.BakingPower > 0) + .Select(x => (x.BakerId, x.BakingPower)) + .ToList()); + + #region temporary diagnostics + await sampler.Validate(Proto, state.Level, cycle.Index); + #endregion + + if (cycle.Index == state.Cycle) + { + shifted = RightsGenerator.GetEndorsingRights(sampler, nextProto, cycle, cycle.LastLevel); + + #region save shifted + using var writer = conn.BeginBinaryImport(""" + COPY "BakingRights" ("Cycle", "Level", "BakerId", "Type", "Status", "Round", "Slots") + FROM STDIN (FORMAT BINARY) + """); + + foreach (var er in shifted) + { + writer.StartRow(); + writer.Write(cycle.Index + 1, NpgsqlTypes.NpgsqlDbType.Integer); + writer.Write(er.Level + 1, NpgsqlTypes.NpgsqlDbType.Integer); + writer.Write(er.Baker, NpgsqlTypes.NpgsqlDbType.Integer); + writer.Write((byte)BakingRightType.Endorsing, NpgsqlTypes.NpgsqlDbType.Smallint); + writer.Write((byte)BakingRightStatus.Future, NpgsqlTypes.NpgsqlDbType.Smallint); + writer.WriteNull(); + writer.Write(er.Slots, NpgsqlTypes.NpgsqlDbType.Integer); + } + + writer.Complete(); + #endregion + } + else + { + GC.Collect(); + var brs = await RightsGenerator.GetBakingRightsAsync(sampler, nextProto, cycle); + var ers = await RightsGenerator.GetEndorsingRightsAsync(sampler, nextProto, cycle); + + #region save rights + using (var writer = conn.BeginBinaryImport(""" + COPY "BakingRights" ("Cycle", "Level", "BakerId", "Type", "Status", "Round", "Slots") + FROM STDIN (FORMAT BINARY) + """)) + { + foreach (var er in ers) + { + writer.StartRow(); + writer.Write(nextProto.GetCycle(er.Level + 1), NpgsqlTypes.NpgsqlDbType.Integer); + writer.Write(er.Level + 1, NpgsqlTypes.NpgsqlDbType.Integer); + writer.Write(er.Baker, NpgsqlTypes.NpgsqlDbType.Integer); + writer.Write((byte)BakingRightType.Endorsing, NpgsqlTypes.NpgsqlDbType.Smallint); + writer.Write((byte)BakingRightStatus.Future, NpgsqlTypes.NpgsqlDbType.Smallint); + writer.WriteNull(); + writer.Write(er.Slots, NpgsqlTypes.NpgsqlDbType.Integer); + } + + foreach (var br in brs) + { + writer.StartRow(); + writer.Write(cycle.Index, NpgsqlTypes.NpgsqlDbType.Integer); + writer.Write(br.Level, NpgsqlTypes.NpgsqlDbType.Integer); + writer.Write(br.Baker, NpgsqlTypes.NpgsqlDbType.Integer); + writer.Write((byte)BakingRightType.Baking, NpgsqlTypes.NpgsqlDbType.Smallint); + writer.Write((byte)BakingRightStatus.Future, NpgsqlTypes.NpgsqlDbType.Smallint); + writer.Write(br.Round, NpgsqlTypes.NpgsqlDbType.Integer); + writer.WriteNull(); + } + + writer.Complete(); + } + #endregion + + #region reset baker cycles + foreach (var bakerCycle in bakerCycles.Values) + { + Db.TryAttach(bakerCycle); + + bakerCycle.FutureBlocks = 0; + bakerCycle.FutureBlockRewards = 0; + bakerCycle.FutureEndorsements = 0; + + var expectedEndorsements = (int)(new BigInteger(nextProto.BlocksPerCycle) * nextProto.EndorsersPerBlock * bakerCycle.BakingPower / cycle.TotalBakingPower); + bakerCycle.ExpectedBlocks = nextProto.BlocksPerCycle * bakerCycle.BakingPower / cycle.TotalBakingPower; + bakerCycle.ExpectedEndorsements = expectedEndorsements; + bakerCycle.FutureEndorsementRewards = expectedEndorsements * cycle.EndorsementRewardPerSlot; + } + + foreach (var br in brs.Where(x => x.Round == 0)) + { + if (!bakerCycles.TryGetValue(br.Baker, out var bakerCycle)) + throw new Exception("Nonexistent baker cycle"); + + bakerCycle.FutureBlocks++; + bakerCycle.FutureBlockRewards += cycle.MaxBlockReward; + } + + foreach (var er in shifted) + { + if (bakerCycles.TryGetValue(er.Baker, out var bakerCycle)) + { + bakerCycle.FutureEndorsements += er.Slots; + } + } + + foreach (var er in ers.TakeWhile(x => x.Level < cycle.LastLevel)) + { + if (!bakerCycles.TryGetValue(er.Baker, out var bakerCycle)) + throw new Exception("Nonexistent baker cycle"); + + bakerCycle.FutureEndorsements += er.Slots; + } + #endregion + + shifted = ers.Where(x => x.Level == cycle.LastLevel).ToList(); + } + } + } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/AutostakingCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/AutostakingCommit.cs new file mode 100644 index 000000000..a3d9b3dfa --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/AutostakingCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class AutostakingCommit : Proto19.AutostakingCommit + { + public AutostakingCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BakerCycleCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BakerCycleCommit.cs new file mode 100644 index 000000000..500b80a9e --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BakerCycleCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class BakerCycleCommit : Proto18.BakerCycleCommit + { + public BakerCycleCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BakingRightsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BakingRightsCommit.cs new file mode 100644 index 000000000..d70dd09ab --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BakingRightsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class BakingRightsCommit : Proto18.BakingRightsCommit + { + public BakingRightsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BigMapCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BigMapCommit.cs new file mode 100644 index 000000000..837a2998b --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BigMapCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class BigMapCommit : Proto1.BigMapCommit + { + public BigMapCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BlockCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BlockCommit.cs new file mode 100644 index 000000000..a204d705c --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/BlockCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class BlockCommit : Proto19.BlockCommit + { + public BlockCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/ContractEventCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/ContractEventCommit.cs new file mode 100644 index 000000000..a2a0b010f --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/ContractEventCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class ContractEventCommit : Proto14.ContractEventCommit + { + public ContractEventCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/CycleCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/CycleCommit.cs new file mode 100644 index 000000000..50b19c667 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/CycleCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class CycleCommit : Proto20.CycleCommit + { + public CycleCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/DeactivationCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/DeactivationCommit.cs new file mode 100644 index 000000000..09c67de32 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/DeactivationCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class DeactivationCommit : Proto2.DeactivationCommit + { + public DeactivationCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/DelegatorCycleCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/DelegatorCycleCommit.cs new file mode 100644 index 000000000..da6d71089 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/DelegatorCycleCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class DelegatorCycleCommit : Proto18.DelegatorCycleCommit + { + public DelegatorCycleCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/EndorsingRewardCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/EndorsingRewardCommit.cs new file mode 100644 index 000000000..36c76e77b --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/EndorsingRewardCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class EndorsingRewardCommit : Proto19.EndorsingRewardCommit + { + public EndorsingRewardCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/InboxCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/InboxCommit.cs new file mode 100644 index 000000000..992e4102b --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/InboxCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + public class InboxCommit : Proto17.InboxCommit + { + public InboxCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/ActivationsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/ActivationsCommit.cs new file mode 100644 index 000000000..38475e7bc --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/ActivationsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class ActivationsCommit : Proto12.ActivationsCommit + { + public ActivationsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/BallotsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/BallotsCommit.cs new file mode 100644 index 000000000..475945e0a --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/BallotsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class BallotsCommit : Proto3.BallotsCommit + { + public BallotsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DalPublishCommitmentCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DalPublishCommitmentCommit.cs new file mode 100644 index 000000000..5c592eb5c --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DalPublishCommitmentCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class DalPublishCommitmentCommit : Proto19.DalPublishCommitmentCommit + { + public DalPublishCommitmentCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DelegationsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DelegationsCommit.cs new file mode 100644 index 000000000..b5e81f5ee --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DelegationsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class DelegationsCommit : Proto18.DelegationsCommit + { + public DelegationsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DoubleBakingCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DoubleBakingCommit.cs new file mode 100644 index 000000000..c8bde955a --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DoubleBakingCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class DoubleBakingCommit : Proto19.DoubleBakingCommit + { + public DoubleBakingCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DoubleEndorsingCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DoubleEndorsingCommit.cs new file mode 100644 index 000000000..f31cd2ee8 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DoubleEndorsingCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class DoubleEndorsingCommit : Proto19.DoubleEndorsingCommit + { + public DoubleEndorsingCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DoublePreendorsingCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DoublePreendorsingCommit.cs new file mode 100644 index 000000000..66c9dc246 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DoublePreendorsingCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class DoublePreendorsingCommit : Proto19.DoublePreendorsingCommit + { + public DoublePreendorsingCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DrainDelegateCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DrainDelegateCommit.cs new file mode 100644 index 000000000..18c67f46c --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/DrainDelegateCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class DrainDelegateCommit : Proto15.DrainDelegateCommit + { + public DrainDelegateCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/EndorsementsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/EndorsementsCommit.cs new file mode 100644 index 000000000..5e4cafde1 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/EndorsementsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class EndorsementsCommit : Proto19.EndorsementsCommit + { + public EndorsementsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/IncreasePaidStorageCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/IncreasePaidStorageCommit.cs new file mode 100644 index 000000000..c4e7d4acf --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/IncreasePaidStorageCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class IncreasePaidStorageCommit : Proto14.IncreasePaidStorageCommit + { + public IncreasePaidStorageCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/NonceRevelationsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/NonceRevelationsCommit.cs new file mode 100644 index 000000000..ceedfdd53 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/NonceRevelationsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class NonceRevelationsCommit : Proto19.NonceRevelationsCommit + { + public NonceRevelationsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/OriginationsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/OriginationsCommit.cs new file mode 100644 index 000000000..d8e5e24c7 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/OriginationsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class OriginationsCommit : Proto14.OriginationsCommit + { + public OriginationsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/PreendorsementsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/PreendorsementsCommit.cs new file mode 100644 index 000000000..bc10aac7c --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/PreendorsementsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class PreendorsementsCommit : Proto19.PreendorsementsCommit + { + public PreendorsementsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/ProposalsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/ProposalsCommit.cs new file mode 100644 index 000000000..504e639dd --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/ProposalsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class ProposalsCommit : Proto14.ProposalsCommit + { + public ProposalsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/RegisterConstantsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/RegisterConstantsCommit.cs new file mode 100644 index 000000000..20ca1715b --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/RegisterConstantsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class RegisterConstantsCommit : Proto14.RegisterConstantsCommit + { + public RegisterConstantsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/RevealsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/RevealsCommit.cs new file mode 100644 index 000000000..b3ec15f5c --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/RevealsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class RevealsCommit : Proto14.RevealsCommit + { + public RevealsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SetDelegateParametersCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SetDelegateParametersCommit.cs new file mode 100644 index 000000000..edd71e604 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SetDelegateParametersCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SetDelegateParametersCommit : Proto18.SetDelegateParametersCommit + { + public SetDelegateParametersCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SetDepositsLimitCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SetDepositsLimitCommit.cs new file mode 100644 index 000000000..7808e6997 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SetDepositsLimitCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SetDepositsLimitCommit : Proto12.SetDepositsLimitCommit + { + public SetDepositsLimitCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupAddMessagesCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupAddMessagesCommit.cs new file mode 100644 index 000000000..bbbf115c5 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupAddMessagesCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SmartRollupAddMessagesCommit : Proto16.SmartRollupAddMessagesCommit + { + public SmartRollupAddMessagesCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupCementCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupCementCommit.cs new file mode 100644 index 000000000..b1fc72989 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupCementCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SmartRollupCementCommit : Proto17.SmartRollupCementCommit + { + public SmartRollupCementCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupExecuteCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupExecuteCommit.cs new file mode 100644 index 000000000..6d3dc65f0 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupExecuteCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SmartRollupExecuteCommit : Proto16.SmartRollupExecuteCommit + { + public SmartRollupExecuteCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupOriginateCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupOriginateCommit.cs new file mode 100644 index 000000000..4487bbdeb --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupOriginateCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SmartRollupOriginateCommit : Proto16.SmartRollupOriginateCommit + { + public SmartRollupOriginateCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupPublishCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupPublishCommit.cs new file mode 100644 index 000000000..2aad079df --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupPublishCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SmartRollupPublishCommit : Proto16.SmartRollupPublishCommit + { + public SmartRollupPublishCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupRecoverBondCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupRecoverBondCommit.cs new file mode 100644 index 000000000..1b5785e30 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupRecoverBondCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SmartRollupRecoverBondCommit : Proto16.SmartRollupRecoverBondCommit + { + public SmartRollupRecoverBondCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupRefuteCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupRefuteCommit.cs new file mode 100644 index 000000000..91ce775a7 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupRefuteCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SmartRollupRefuteCommit : Proto16.SmartRollupRefuteCommit + { + public SmartRollupRefuteCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupTimeoutCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupTimeoutCommit.cs new file mode 100644 index 000000000..0689c9a47 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/SmartRollupTimeoutCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SmartRollupTimeoutCommit : Proto16.SmartRollupTimeoutCommit + { + public SmartRollupTimeoutCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/StakingCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/StakingCommit.cs new file mode 100644 index 000000000..f706bb5b5 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/StakingCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class StakingCommit : Proto19.StakingCommit + { + public StakingCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/TransactionsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/TransactionsCommit.cs new file mode 100644 index 000000000..d8a6b2bda --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/TransactionsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class TransactionsCommit : Proto14.TransactionsCommit + { + public TransactionsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/TransferTicketCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/TransferTicketCommit.cs new file mode 100644 index 000000000..5706aa7f5 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/TransferTicketCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class TransferTicketCommit : Proto13.TransferTicketCommit + { + public TransferTicketCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/UpdateConsensusKeyCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/UpdateConsensusKeyCommit.cs new file mode 100644 index 000000000..88529b3e8 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/UpdateConsensusKeyCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class UpdateConsensusKeyCommit : Proto15.UpdateConsensusKeyCommit + { + public UpdateConsensusKeyCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/VdfRevelationCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/VdfRevelationCommit.cs new file mode 100644 index 000000000..f2487df16 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/Operations/VdfRevelationCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class VdfRevelationCommit : Proto19.VdfRevelationCommit + { + public VdfRevelationCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SlashingCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SlashingCommit.cs new file mode 100644 index 000000000..5b44d0138 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SlashingCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SlashingCommit : Proto19.SlashingCommit + { + public SlashingCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SnapshotBalanceCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SnapshotBalanceCommit.cs new file mode 100644 index 000000000..4f5ce8620 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SnapshotBalanceCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SnapshotBalanceCommit : Proto19.SnapshotBalanceCommit + { + public SnapshotBalanceCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SoftwareCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SoftwareCommit.cs new file mode 100644 index 000000000..32bed6564 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SoftwareCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SoftwareCommit : Proto5.SoftwareCommit + { + public SoftwareCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/StakingUpdateCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/StakingUpdateCommit.cs new file mode 100644 index 000000000..3e441337d --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/StakingUpdateCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class StakingUpdateCommit : Proto18.StakingUpdateCommit + { + public StakingUpdateCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/StateCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/StateCommit.cs new file mode 100644 index 000000000..29e6e7dbb --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/StateCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class StateCommit : Proto1.StateCommit + { + public StateCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/StatisticsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/StatisticsCommit.cs new file mode 100644 index 000000000..61b8de46f --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/StatisticsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class StatisticsCommit : Proto1.StatisticsCommit + { + public StatisticsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SubsidyCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SubsidyCommit.cs new file mode 100644 index 000000000..d8fdd9632 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/SubsidyCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class SubsidyCommit : Proto10.SubsidyCommit + { + public SubsidyCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/TicketsCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/TicketsCommit.cs new file mode 100644 index 000000000..02901dcb9 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/TicketsCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class TicketsCommit : Proto16.TicketsCommit + { + public TicketsCommit(ProtocolHandler protocol) : base(protocol) { } + } +} \ No newline at end of file diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/TokensCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/TokensCommit.cs new file mode 100644 index 000000000..4c4a56fb5 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/TokensCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class TokensCommit : Proto5.TokensCommit + { + public TokensCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/VotingCommit.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/VotingCommit.cs new file mode 100644 index 000000000..08d3751ae --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Commits/VotingCommit.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class VotingCommit : Proto13.VotingCommit + { + public VotingCommit(ProtocolHandler protocol) : base(protocol) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Diagnostics/Diagnostics.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Diagnostics/Diagnostics.cs new file mode 100644 index 000000000..ecb521af3 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Diagnostics/Diagnostics.cs @@ -0,0 +1,7 @@ +namespace Tzkt.Sync.Protocols.Proto21 +{ + class Diagnostics : Proto18.Diagnostics + { + public Diagnostics(ProtocolHandler handler) : base(handler) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Proto21Handler.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Proto21Handler.cs new file mode 100644 index 000000000..1a3c2167c --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Proto21Handler.cs @@ -0,0 +1,621 @@ +using System.Text.Json; +using Microsoft.EntityFrameworkCore; +using App.Metrics; +using Tzkt.Data; +using Tzkt.Data.Models; +using Tzkt.Data.Models.Base; +using Tzkt.Sync.Services; +using Tzkt.Sync.Protocols.Proto21; + +namespace Tzkt.Sync.Protocols +{ + class Proto21Handler : ProtocolHandler + { + public override IDiagnostics Diagnostics { get; } + public override IValidator Validator { get; } + public override IRpc Rpc { get; } + public override string VersionName => "beta"; + public override int VersionNumber => 21; + + public Proto21Handler(TezosNode node, TzktContext db, CacheService cache, QuotesService quotes, IServiceProvider services, IConfiguration config, ILogger logger, IMetrics metrics) + : base(node, db, cache, quotes, services, config, logger, metrics) + { + Rpc = new Rpc(node); + Diagnostics = new Diagnostics(this); + Validator = new Validator(this); + } + + public override Task Activate(AppState state, JsonElement block) => new ProtoActivator(this).Activate(state, block); + public override Task Deactivate(AppState state) => new ProtoActivator(this).Deactivate(state); + + public override async Task Commit(JsonElement block) + { + await new StatisticsCommit(this).Apply(block); + + var blockCommit = new BlockCommit(this); + await blockCommit.Apply(block); + + var cycleCommit = new CycleCommit(this); + await cycleCommit.Apply(blockCommit.Block); + + await new SetDelegateParametersCommit(this).ActivateStakingParameters(blockCommit.Block); + + await new SoftwareCommit(this).Apply(blockCommit.Block, block); + await new DeactivationCommit(this).Apply(blockCommit.Block, block); + + #region implicit operations + foreach (var op in block + .Required("metadata") + .RequiredArray("implicit_operations_results") + .EnumerateArray() + .Where(x => x.RequiredString("kind") == "transaction")) + await new SubsidyCommit(this).Apply(blockCommit.Block, op); + #endregion + + var operations = block.RequiredArray("operations", 4); + + #region operations 0 + foreach (var operation in operations[0].EnumerateArray()) + { + foreach (var content in operation.RequiredArray("contents", 1).EnumerateArray()) + { + switch (content.RequiredString("kind")) + { + case "attestation": + case "attestation_with_dal": + await new EndorsementsCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "preattestation": + case "preattestation_with_dal": + new PreendorsementsCommit(this).Apply(blockCommit.Block, operation, content); + break; + default: + throw new NotImplementedException($"'{content.RequiredString("kind")}' is not allowed in operations[0]"); + } + } + } + #endregion + + #region operations 1 + var dictatorSeen = false; + foreach (var operation in operations[1].EnumerateArray()) + { + foreach (var content in operation.RequiredArray("contents", 1).EnumerateArray()) + { + switch (content.RequiredString("kind")) + { + case "proposals": + var proposalsCommit = new ProposalsCommit(this); + await proposalsCommit.Apply(blockCommit.Block, operation, content); + dictatorSeen = proposalsCommit.DictatorSeen; + break; + case "ballot": + await new BallotsCommit(this).Apply(blockCommit.Block, operation, content); + break; + default: + throw new NotImplementedException($"'{content.RequiredString("kind")}' is not allowed in operations[1]"); + } + } + if (dictatorSeen) break; + } + #endregion + + #region operations 2 + foreach (var operation in operations[2].EnumerateArray()) + { + foreach (var content in operation.RequiredArray("contents", 1).EnumerateArray()) + { + switch (content.RequiredString("kind")) + { + case "activate_account": + await new ActivationsCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "double_baking_evidence": + await new DoubleBakingCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "double_attestation_evidence": + await new DoubleEndorsingCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "double_preattestation_evidence": + await new DoublePreendorsingCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "seed_nonce_revelation": + await new NonceRevelationsCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "vdf_revelation": + await new VdfRevelationCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "drain_delegate": + await new DrainDelegateCommit(this).Apply(blockCommit.Block, operation, content); + break; + default: + throw new NotImplementedException($"'{content.RequiredString("kind")}' is not allowed in operations[2]"); + } + } + } + #endregion + + var bigMapCommit = new BigMapCommit(this); + var ticketsCommit = new TicketsCommit(this); + + #region operations 3 + foreach (var operation in operations[3].EnumerateArray()) + { + Manager.Init(operation); + foreach (var content in operation.RequiredArray("contents").EnumerateArray()) + { + switch (content.RequiredString("kind")) + { + case "set_deposits_limit": + await new SetDepositsLimitCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "increase_paid_storage": + await new IncreasePaidStorageCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "update_consensus_key": + await new UpdateConsensusKeyCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "reveal": + await new RevealsCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "register_global_constant": + await new RegisterConstantsCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "delegation": + await new DelegationsCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "origination": + var orig = new OriginationsCommit(this); + await orig.Apply(blockCommit.Block, operation, content); + if (orig.BigMapDiffs != null) + bigMapCommit.Append(orig.Origination, orig.Origination.Contract, orig.BigMapDiffs); + break; + case "transaction": + var src = content.RequiredString("source"); + var dst = content.RequiredString("destination"); + if (src == dst && + src.StartsWith("tz") && + content.Optional("parameters")?.RequiredString("entrypoint") is string entrypoint) + { + if (Proto18.StakingCommit.Entrypoints.Contains(entrypoint)) + { + await new StakingCommit(this).Apply(blockCommit.Block, operation, content); + break; + } + else if (Proto18.SetDelegateParametersCommit.Entrypoint == entrypoint) + { + await new SetDelegateParametersCommit(this).Apply(blockCommit.Block, operation, content); + break; + } + } + + var parent = new TransactionsCommit(this); + await parent.Apply(blockCommit.Block, operation, content); + if (parent.BigMapDiffs != null) + bigMapCommit.Append(parent.Transaction, parent.Transaction.Target as Contract, parent.BigMapDiffs); + if (parent.TicketUpdates != null) + ticketsCommit.Append(parent.Transaction, parent.Transaction, parent.TicketUpdates); + + if (content.Required("metadata").TryGetProperty("internal_operation_results", out var internalResult)) + { + foreach (var internalContent in internalResult.EnumerateArray()) + { + switch (internalContent.RequiredString("kind")) + { + case "delegation": + await new DelegationsCommit(this).ApplyInternal(blockCommit.Block, parent.Transaction, internalContent); + break; + case "origination": + var internalOrig = new OriginationsCommit(this); + await internalOrig.ApplyInternal(blockCommit.Block, parent.Transaction, internalContent); + if (internalOrig.BigMapDiffs != null) + bigMapCommit.Append(internalOrig.Origination, internalOrig.Origination.Contract, internalOrig.BigMapDiffs); + break; + case "transaction": + var internalTx = new TransactionsCommit(this); + await internalTx.ApplyInternal(blockCommit.Block, parent.Transaction, internalContent); + if (internalTx.BigMapDiffs != null) + bigMapCommit.Append(internalTx.Transaction, internalTx.Transaction.Target as Contract, internalTx.BigMapDiffs); + if (internalTx.TicketUpdates != null) + ticketsCommit.Append(parent.Transaction, internalTx.Transaction, internalTx.TicketUpdates); + break; + case "event": + await new ContractEventCommit(this).Apply(blockCommit.Block, internalContent); + break; + default: + throw new NotImplementedException($"internal '{internalContent.RequiredString("kind")}' is not implemented"); + } + } + } + break; + case "transfer_ticket": + var parent1 = new TransferTicketCommit(this); + await parent1.Apply(blockCommit.Block, operation, content); + if (parent1.TicketUpdates != null) + ticketsCommit.Append(parent1.Operation, parent1.Operation, parent1.TicketUpdates); + if (content.Required("metadata").TryGetProperty("internal_operation_results", out var internalResult1)) + { + foreach (var internalContent in internalResult1.EnumerateArray()) + { + switch (internalContent.RequiredString("kind")) + { + case "transaction": + var internalTx = new TransactionsCommit(this); + await internalTx.ApplyInternal(blockCommit.Block, parent1.Operation, internalContent); + if (internalTx.BigMapDiffs != null) + bigMapCommit.Append(internalTx.Transaction, internalTx.Transaction.Target as Contract, internalTx.BigMapDiffs); + if (internalTx.TicketUpdates != null) + ticketsCommit.Append(parent1.Operation, internalTx.Transaction, internalTx.TicketUpdates); + break; + case "event": + await new ContractEventCommit(this).Apply(blockCommit.Block, internalContent); + break; + default: + throw new NotImplementedException($"internal '{internalContent.RequiredString("kind")}' inside 'transfer_ticket' is not expected"); + } + } + } + break; + case "smart_rollup_add_messages": + await new SmartRollupAddMessagesCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "smart_rollup_cement": + await new SmartRollupCementCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "smart_rollup_execute_outbox_message": + var parent2 = new SmartRollupExecuteCommit(this); + await parent2.Apply(blockCommit.Block, operation, content); + if (parent2.TicketUpdates != null) + ticketsCommit.Append(parent2.Operation, parent2.Operation, parent2.TicketUpdates); + if (content.Required("metadata").TryGetProperty("internal_operation_results", out var internalResult2)) + { + foreach (var internalContent in internalResult2.EnumerateArray()) + { + switch (internalContent.RequiredString("kind")) + { + case "delegation": + await new DelegationsCommit(this).ApplyInternal(blockCommit.Block, parent2.Operation, internalContent); + break; + case "origination": + var internalOrig = new OriginationsCommit(this); + await internalOrig.ApplyInternal(blockCommit.Block, parent2.Operation, internalContent); + if (internalOrig.BigMapDiffs != null) + bigMapCommit.Append(internalOrig.Origination, internalOrig.Origination.Contract, internalOrig.BigMapDiffs); + break; + case "transaction": + var internalTx = new TransactionsCommit(this); + await internalTx.ApplyInternal(blockCommit.Block, parent2.Operation, internalContent); + if (internalTx.BigMapDiffs != null) + bigMapCommit.Append(internalTx.Transaction, internalTx.Transaction.Target as Contract, internalTx.BigMapDiffs); + if (internalTx.TicketUpdates != null) + ticketsCommit.Append(parent2.Operation, internalTx.Transaction, internalTx.TicketUpdates); + break; + case "event": + await new ContractEventCommit(this).Apply(blockCommit.Block, internalContent); + break; + default: + throw new NotImplementedException($"internal '{internalContent.RequiredString("kind")}' is not implemented"); + } + } + } + break; + case "smart_rollup_originate": + await new SmartRollupOriginateCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "smart_rollup_publish": + await new SmartRollupPublishCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "smart_rollup_recover_bond": + await new SmartRollupRecoverBondCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "smart_rollup_refute": + await new SmartRollupRefuteCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "smart_rollup_timeout": + await new SmartRollupTimeoutCommit(this).Apply(blockCommit.Block, operation, content); + break; + case "dal_publish_commitment": + await new DalPublishCommitmentCommit(this).Apply(blockCommit.Block, operation, content); + break; + default: + throw new NotImplementedException($"'{content.RequiredString("kind")}' is not expected in operations[3]"); + } + } + Manager.Reset(); + } + #endregion + + await blockCommit.ApplyRewards(block); + + new InboxCommit(this).Apply(blockCommit.Block); + + await bigMapCommit.Apply(); + await ticketsCommit.Apply(); + await new TokensCommit(this).Apply(blockCommit.Block, bigMapCommit.Updates); + + var brCommit = new BakingRightsCommit(this); + await brCommit.Apply(blockCommit.Block, cycleCommit.FutureCycle, cycleCommit.SelectedStakes); + + await new DelegatorCycleCommit(this).Apply(blockCommit.Block, cycleCommit.FutureCycle); + + await new BakerCycleCommit(this).Apply( + blockCommit.Block, + cycleCommit.FutureCycle, + brCommit.FutureBakingRights, + brCommit.FutureEndorsingRights, + cycleCommit.Snapshots, + cycleCommit.SelectedStakes, + brCommit.CurrentRights); + + await new EndorsingRewardCommit(this).Apply(blockCommit.Block, block); + await new StateCommit(this).Apply(blockCommit.Block, block); + } + + public override async Task AfterCommit(JsonElement rawBlock) + { + var block = await Cache.Blocks.CurrentAsync(); + await new SlashingCommit(this).Apply(block, rawBlock); + await new VotingCommit(this).Apply(block, rawBlock); + await new AutostakingCommit(this).Apply(block, rawBlock); + + Diagnostics.TrackChanges(); + await Db.SaveChangesAsync(); + + await new SnapshotBalanceCommit(this).Apply(rawBlock, block); + } + + public override async Task BeforeRevert() + { + var block = await Cache.Blocks.CurrentAsync(); + await new SnapshotBalanceCommit(this).Revert(block); + await new AutostakingCommit(this).Revert(block); + await new VotingCommit(this).Revert(block); + await new SlashingCommit(this).Revert(block); + } + + public override async Task Revert() + { + var currBlock = await Cache.Blocks.CurrentAsync(); + Db.TryAttach(currBlock); + + #region load operations + var operations = new List(40); + + if (currBlock.Operations.HasFlag(Operations.Activations)) + operations.AddRange(await Db.ActivationOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.Delegations)) + operations.AddRange(await Db.DelegationOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.Endorsements)) + operations.AddRange(await Db.EndorsementOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.Preendorsements)) + operations.AddRange(await Db.PreendorsementOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.Originations)) + operations.AddRange(await Db.OriginationOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.Reveals)) + operations.AddRange(await Db.RevealOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.SetDepositsLimits)) + operations.AddRange(await Db.SetDepositsLimitOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.SetDelegateParameters)) + operations.AddRange(await Db.SetDelegateParametersOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.RegisterConstant)) + operations.AddRange(await Db.RegisterConstantOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.IncreasePaidStorage)) + operations.AddRange(await Db.IncreasePaidStorageOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.UpdateConsensusKey)) + operations.AddRange(await Db.UpdateConsensusKeyOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.Revelations)) + operations.AddRange(await Db.NonceRevelationOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.VdfRevelation)) + operations.AddRange(await Db.VdfRevelationOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.Staking)) + operations.AddRange(await Db.StakingOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.Transactions)) + operations.AddRange(await Db.TransactionOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.TransferTicket)) + operations.AddRange(await Db.TransferTicketOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.DoubleBakings)) + operations.AddRange(await Db.DoubleBakingOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.DoubleEndorsings)) + operations.AddRange(await Db.DoubleEndorsingOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.DoublePreendorsings)) + operations.AddRange(await Db.DoublePreendorsingOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.DrainDelegate)) + operations.AddRange(await Db.DrainDelegateOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.Ballots)) + operations.AddRange(await Db.BallotOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.Proposals)) + operations.AddRange(await Db.ProposalOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.RevelationPenalty)) + await Db.Entry(currBlock).Collection(x => x.RevelationPenalties).LoadAsync(); + + if (currBlock.Operations.HasFlag(Operations.Migrations)) + await Db.Entry(currBlock).Collection(x => x.Migrations).LoadAsync(); + + if (currBlock.Operations.HasFlag(Operations.SmartRollupAddMessages)) + operations.AddRange(await Db.SmartRollupAddMessagesOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.SmartRollupCement)) + operations.AddRange(await Db.SmartRollupCementOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.SmartRollupExecute)) + operations.AddRange(await Db.SmartRollupExecuteOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.SmartRollupOriginate)) + operations.AddRange(await Db.SmartRollupOriginateOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.SmartRollupPublish)) + operations.AddRange(await Db.SmartRollupPublishOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.SmartRollupRecoverBond)) + operations.AddRange(await Db.SmartRollupRecoverBondOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.SmartRollupRefute)) + operations.AddRange(await Db.SmartRollupRefuteOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Operations.HasFlag(Operations.DalPublishCommitment)) + operations.AddRange(await Db.DalPublishCommitmentOps.Where(x => x.Level == currBlock.Level).ToListAsync()); + + if (currBlock.Events.HasFlag(BlockEvents.NewAccounts)) + { + await Db.Entry(currBlock).Collection(x => x.CreatedAccounts).LoadAsync(); + foreach (var account in currBlock.CreatedAccounts) + Cache.Accounts.Add(account); + } + #endregion + + await new StatisticsCommit(this).Revert(currBlock); + + await new EndorsingRewardCommit(this).Revert(currBlock); + + await new BakerCycleCommit(this).Revert(currBlock); + await new DelegatorCycleCommit(this).Revert(currBlock); + await new BakingRightsCommit(this).Revert(currBlock); + await new TokensCommit(this).Revert(currBlock); + await new TicketsCommit(this).Revert(currBlock); + await new BigMapCommit(this).Revert(currBlock); + await new ContractEventCommit(this).Revert(currBlock); + await new InboxCommit(this).Revert(currBlock); + await new BlockCommit(this).RevertRewards(currBlock); + + foreach (var operation in operations.OrderByDescending(x => x.Id)) + { + switch (operation) + { + case EndorsementOperation op: + await new EndorsementsCommit(this).Revert(currBlock, op); + break; + case PreendorsementOperation op: + await new PreendorsementsCommit(this).Revert(currBlock, op); + break; + case ProposalOperation op: + await new ProposalsCommit(this).Revert(currBlock, op); + break; + case BallotOperation op: + await new BallotsCommit(this).Revert(currBlock, op); + break; + case ActivationOperation op: + await new ActivationsCommit(this).Revert(currBlock, op); + break; + case DoubleBakingOperation op: + new DoubleBakingCommit(this).Revert(op); + break; + case DoubleEndorsingOperation op: + new DoubleEndorsingCommit(this).Revert(op); + break; + case DoublePreendorsingOperation op: + new DoublePreendorsingCommit(this).Revert(op); + break; + case NonceRevelationOperation op: + await new NonceRevelationsCommit(this).Revert(currBlock, op); + break; + case VdfRevelationOperation op: + await new VdfRevelationCommit(this).Revert(currBlock, op); + break; + case DrainDelegateOperation op: + await new DrainDelegateCommit(this).Revert(currBlock, op); + break; + case RevealOperation op: + await new RevealsCommit(this).Revert(currBlock, op); + break; + case IncreasePaidStorageOperation op: + await new IncreasePaidStorageCommit(this).Revert(currBlock, op); + break; + case UpdateConsensusKeyOperation op: + await new UpdateConsensusKeyCommit(this).Revert(currBlock, op); + break; + case RegisterConstantOperation registerConstant: + await new RegisterConstantsCommit(this).Revert(currBlock, registerConstant); + break; + case SetDepositsLimitOperation setDepositsLimit: + await new SetDepositsLimitCommit(this).Revert(currBlock, setDepositsLimit); + break; + case DelegationOperation op: + if (op.InitiatorId == null) + await new DelegationsCommit(this).Revert(currBlock, op); + else + await new DelegationsCommit(this).RevertInternal(currBlock, op); + break; + case OriginationOperation op: + if (op.InitiatorId == null) + await new OriginationsCommit(this).Revert(currBlock, op); + else + await new OriginationsCommit(this).RevertInternal(currBlock, op); + break; + case StakingOperation op: + await new StakingCommit(this).Revert(currBlock, op); + break; + case SetDelegateParametersOperation op: + await new SetDelegateParametersCommit(this).Revert(currBlock, op); + break; + case TransactionOperation op: + if (op.InitiatorId == null) + await new TransactionsCommit(this).Revert(currBlock, op); + else + await new TransactionsCommit(this).RevertInternal(currBlock, op); + break; + case TransferTicketOperation op: + await new TransferTicketCommit(this).Revert(currBlock, op); + break; + case SmartRollupAddMessagesOperation op: + await new SmartRollupAddMessagesCommit(this).Revert(currBlock, op); + break; + case SmartRollupCementOperation op: + await new SmartRollupCementCommit(this).Revert(currBlock, op); + break; + case SmartRollupExecuteOperation op: + await new SmartRollupExecuteCommit(this).Revert(currBlock, op); + break; + case SmartRollupOriginateOperation op: + await new SmartRollupOriginateCommit(this).Revert(currBlock, op); + break; + case SmartRollupPublishOperation op: + await new SmartRollupPublishCommit(this).Revert(currBlock, op); + break; + case SmartRollupRecoverBondOperation op: + await new SmartRollupRecoverBondCommit(this).Revert(currBlock, op); + break; + case SmartRollupRefuteOperation op: + await new SmartRollupRefuteCommit(this).Revert(currBlock, op); + break; + case DalPublishCommitmentOperation op: + await new DalPublishCommitmentCommit(this).Revert(currBlock, op); + break; + default: + throw new NotImplementedException($"'{operation.GetType()}' is not implemented"); + } + } + + await new SubsidyCommit(this).Revert(currBlock); + + await new DeactivationCommit(this).Revert(currBlock); + await new SoftwareCommit(this).Revert(currBlock); + await new SetDelegateParametersCommit(this).DeactivateStakingParameters(currBlock); + await new CycleCommit(this).Revert(currBlock); + new BlockCommit(this).Revert(currBlock); + + await new StateCommit(this).Revert(currBlock); + } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Rpc/Rpc.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Rpc/Rpc.cs new file mode 100644 index 000000000..2d6f2ede7 --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Rpc/Rpc.cs @@ -0,0 +1,9 @@ +using Tzkt.Sync.Services; + +namespace Tzkt.Sync.Protocols.Proto21 +{ + class Rpc : Proto19.Rpc + { + public Rpc(TezosNode node) : base(node) { } + } +} diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Validation/Validator.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Validation/Validator.cs new file mode 100644 index 000000000..c72f3731a --- /dev/null +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Validation/Validator.cs @@ -0,0 +1,1028 @@ +using System.Text.Json; +using Tzkt.Data.Models; +using Tzkt.Sync.Services; + +namespace Tzkt.Sync.Protocols.Proto21 +{ + class Validator : IValidator + { + readonly CacheService Cache; + Protocol Protocol; + string Proposer; + string Producer; + int Level; + int Cycle; + + public Validator(ProtocolHandler protocol) => Cache = protocol.Cache; + + public virtual async Task ValidateBlock(JsonElement block) + { + Protocol = await Cache.Protocols.GetAsync(Cache.AppState.GetNextProtocol()); + + if (block.RequiredString("chain_id") != Cache.AppState.GetChainId()) + throw new ValidationException("invalid chain"); + + if (block.RequiredString("protocol") != Cache.AppState.GetNextProtocol()) + throw new ValidationException("invalid block protocol", true); + + ValidateBlockHeader(block.Required("header")); + await ValidateBlockMetadata(block.Required("metadata")); + await ValidateOperations(block.RequiredArray("operations", 4)); + } + + void ValidateBlockHeader(JsonElement header) + { + Level = header.RequiredInt32("level"); + if (Level != Cache.AppState.GetNextLevel()) + throw new ValidationException($"invalid block level", true); + + if (header.RequiredString("predecessor") != Cache.AppState.GetHead()) + throw new ValidationException($"invalid block predecessor", true); + } + + async Task ValidateBlockMetadata(JsonElement metadata) + { + #region baking + Proposer = metadata.RequiredString("proposer"); + if (!Cache.Accounts.DelegateExists(Proposer)) + throw new ValidationException($"non-existent block proposer"); + + Producer = metadata.RequiredString("baker"); + if (!Cache.Accounts.DelegateExists(Producer)) + throw new ValidationException($"non-existent block baker"); + #endregion + + #region level info + Cycle = metadata.Required("level_info").RequiredInt32("cycle"); + if (Cycle != Protocol.GetCycle(Level)) + throw new ValidationException($"invalid block cycle", true); + #endregion + + #region voting info + var periodInfo = metadata.Required("voting_period_info").Required("voting_period"); + var periodIndex = periodInfo.RequiredInt32("index"); + var periodKind = periodInfo.RequiredString("kind") switch + { + "proposal" => PeriodKind.Proposal, + "exploration" => PeriodKind.Exploration, + "cooldown" => PeriodKind.Testing, + "promotion" => PeriodKind.Promotion, + "adoption" => PeriodKind.Adoption, + _ => throw new ValidationException("invalid voting period kind") + }; + + var period = await Cache.Periods.GetAsync(Cache.AppState.Get().VotingPeriod); + if (Level > period.FirstLevel && Level < period.LastLevel) + { + if (periodIndex != period.Index) + throw new ValidationException("invalid voting period index"); + + if (!Protocol.HasDictator && periodKind != period.Kind) + throw new ValidationException("unexpected voting period"); + } + #endregion + + #region deactivation + foreach (var baker in metadata.RequiredArray("deactivated").EnumerateArray()) + if (!Cache.Accounts.DelegateExists(baker.GetString())) + throw new ValidationException($"non-existent deactivated baker {baker}"); + #endregion + + #region balance updates + var balanceUpdates = metadata.RequiredArray("balance_updates").EnumerateArray(); + if (balanceUpdates.Any(x => x.RequiredString("kind") == "contract" && x.RequiredString("origin") == "block" && !Cache.Accounts.DelegateExists(x.RequiredString("contract")))) + throw new ValidationException("non-existent delegate in block balance updates"); + + if (Cycle < Protocol.NoRewardCycles) + { + if (balanceUpdates.Any(x => x.RequiredString("kind") == "minted" && x.RequiredString("category") == "baking rewards")) + throw new ValidationException("unexpected block reward"); + + if (balanceUpdates.Any(x => x.RequiredString("kind") == "minted" && x.RequiredString("category") == "baking bonuses")) + throw new ValidationException("unexpected block bonus"); + } + else + { + if (balanceUpdates.Count(x => x.RequiredString("kind") == "minted" && x.RequiredString("category") == "baking rewards") > 4) + throw new ValidationException("invalid block reward"); + + if (balanceUpdates.Count(x => x.RequiredString("kind") == "minted" && x.RequiredString("category") == "baking bonuses") > 4) + throw new ValidationException("invalid block bonus"); + } + #endregion + + #region implicit operations + foreach (var op in metadata.RequiredArray("implicit_operations_results").EnumerateArray()) + { + var kind = op.RequiredString("kind"); + if (kind == "transaction") + { + var subsidy = op.RequiredArray("balance_updates", 2).EnumerateArray() + .Where(x => x.RequiredString("kind") == "contract"); + + if (subsidy.Count() > 1) + throw new ValidationException("invalid subsidy"); + + if (subsidy.Any(x => x.RequiredString("origin") != "subsidy")) + throw new ValidationException("invalid subsidy origin"); + + if (subsidy.Any(x => x.RequiredString("contract") != Proto10.ProtoActivator.CpmmContract)) + throw new ValidationException("invalid subsidy recepient"); + } + else if (kind == "origination" && Level == Protocol.FirstLevel) + { + var contract = op.RequiredArray("originated_contracts", 1)[0].RequiredString(); + if (!await Cache.Accounts.ExistsAsync(contract, AccountType.Contract)) + throw new ValidationException("unexpected implicit origination"); + } + else + { + throw new ValidationException("unexpected implicit operation kind"); + } + } + #endregion + } + + protected virtual async Task ValidateOperations(JsonElement operations) + { + foreach (var opg in operations.EnumerateArray()) + { + foreach (var op in opg.RequiredArray().EnumerateArray()) + { + foreach (var content in op.RequiredArray("contents").EnumerateArray()) + { + switch (content.RequiredString("kind")) + { + case "attestation": ValidateAttestation(content); break; + case "attestation_with_dal": ValidateAttestation(content); break; + case "preattestation": ValidatePreattestation(content); break; + case "preattestation_with_dal": ValidatePreattestation(content); break; + case "ballot": await ValidateBallot(content); break; + case "proposals": ValidateProposal(content); break; + case "activate_account": await ValidateActivation(content); break; + case "double_baking_evidence": ValidateDoubleBaking(content); break; + case "double_attestation_evidence": ValidateDoubleBaking(content); break; + case "double_preattestation_evidence": ValidateDoubleBaking(content); break; + case "seed_nonce_revelation": await ValidateSeedNonceRevelation(content); break; + case "vdf_revelation": ValidateVdfRevelation(content); break; + case "drain_delegate": ValidateDrainDelegate(content); break; + case "delegation": await ValidateDelegation(content); break; + case "origination": await ValidateOrigination(content); break; + case "transaction": await ValidateTransaction(content); break; + case "reveal": await ValidateReveal(content); break; + case "register_global_constant": await ValidateRegisterConstant(content); break; + case "set_deposits_limit": await ValidateSetDepositsLimit(content); break; + case "increase_paid_storage": await ValidateIncreasePaidStorage(content); break; + case "update_consensus_key": await ValidateUpdateConsensusKey(content); break; + case "tx_rollup_origination": await ValidateTxRollupOrigination(content); break; + case "tx_rollup_submit_batch": await ValidateTxRollupSubmitBatch(content); break; + case "tx_rollup_commit": await ValidateTxRollupCommit(content); break; + case "tx_rollup_finalize_commitment": await ValidateTxRollupFinalizeCommitment(content); break; + case "tx_rollup_remove_commitment": await ValidateTxRollupRemoveCommitment(content); break; + case "tx_rollup_return_bond": await ValidateTxRollupReturnBond(content); break; + case "tx_rollup_rejection": await ValidateTxRollupRejection(content); break; + case "tx_rollup_dispatch_tickets": await ValidateTxRollupDispatchTickets(content); break; + case "transfer_ticket": await ValidateTransferTicket(content); break; + case "smart_rollup_add_messages": await ValidateSmartRollupAddMessages(content); break; + case "smart_rollup_cement": await ValidateSmartRollupCement(content); break; + case "smart_rollup_execute_outbox_message": await ValidateSmartRollupExecute(content); break; + case "smart_rollup_originate": await ValidateSmartRollupOriginate(content); break; + case "smart_rollup_publish": await ValidateSmartRollupPublish(content); break; + case "smart_rollup_recover_bond": await ValidateSmartRollupRecoverBond(content); break; + case "smart_rollup_refute": await ValidateSmartRollupRefute(content); break; + case "smart_rollup_timeout": await ValidateSmartRollupTimeout(content); break; + case "dal_publish_commitment": await ValidateDalPublishCommitment(content); break; + default: + throw new ValidationException("invalid operation content kind"); + } + } + } + } + } + + protected virtual void ValidateAttestation(JsonElement content) + { + if (content.RequiredInt32("level") != Cache.AppState.GetLevel()) + throw new ValidationException("invalid attestation level"); + + if (!Cache.Accounts.DelegateExists(content.Required("metadata").RequiredString("delegate"))) + throw new ValidationException("unknown attestation delegate"); + } + + protected virtual void ValidatePreattestation(JsonElement content) + { + if (content.RequiredInt32("level") != Cache.AppState.GetLevel() + 1) + throw new ValidationException("invalid preattestation level"); + + if (!Cache.Accounts.DelegateExists(content.Required("metadata").RequiredString("delegate"))) + throw new ValidationException("unknown preattestation delegate"); + } + + protected virtual async Task ValidateBallot(JsonElement content) + { + var periodIndex = content.RequiredInt32("period"); + + if (Cache.AppState.Get().VotingPeriod != periodIndex) + throw new ValidationException("invalid ballot voting period"); + + var proposal = await Cache.Proposals.GetOrDefaultAsync(Cache.AppState.Get().VotingEpoch, content.RequiredString("proposal")); + if (proposal?.Status != ProposalStatus.Active) + throw new ValidationException("invalid ballot proposal"); + + if (!Cache.Accounts.DelegateExists(content.RequiredString("source"))) + throw new ValidationException("invalid ballot sender"); + } + + protected virtual void ValidateProposal(JsonElement content) + { + var periodIndex = content.RequiredInt32("period"); + + if (Cache.AppState.Get().VotingPeriod != periodIndex) + throw new ValidationException("invalid proposal voting period"); + + var source = content.RequiredString("source"); + if (Protocol.Dictator != source && !Cache.Accounts.DelegateExists(source)) + throw new ValidationException("invalid proposal sender"); + } + + protected virtual async Task ValidateActivation(JsonElement content) + { + var account = content.RequiredString("pkh"); + + if (await Cache.Accounts.ExistsAsync(account, AccountType.User) && + ((await Cache.Accounts.GetAsync(account)) as User).ActivationsCount > 0) + throw new ValidationException("account is already activated"); + + if (content.Required("metadata").RequiredArray("balance_updates", 2)[1].RequiredString("contract") != account) + throw new ValidationException("invalid activation balance updates"); + } + + protected virtual void ValidateDoubleBaking(JsonElement content) + { + } + + protected virtual async Task ValidateSeedNonceRevelation(JsonElement content) + { + var level = content.RequiredInt32("level"); + var proto = await Cache.Protocols.FindByLevelAsync(level); + + if ((level - Cache.Protocols.GetCycleStart(proto.GetCycle(level)) + 1) % proto.BlocksPerCommitment != 0) + throw new ValidationException("invalid seed nonce revelation level"); + + var balanceUpdates = content.Required("metadata").RequiredArray("balance_updates").EnumerateArray(); + + if (balanceUpdates.Count() % 2 != 0) + throw new ValidationException("invalid seed nonce revelation balance updates count"); + + if (balanceUpdates.Any(x => + x.RequiredString("kind") == "contract" && Proposer != x.RequiredString("contract") || + x.RequiredString("kind") == "freezer" && Proposer != ( + x.Required("staker").Optional("baker_own_stake")?.GetString() + ?? x.Required("staker").Optional("baker_edge")?.GetString() + ?? x.Required("staker").Required("delegate").GetString() + ))) + throw new ValidationException("invalid seed nonce revelation baker"); + } + + protected virtual void ValidateVdfRevelation(JsonElement content) + { + var balanceUpdates = content.Required("metadata").RequiredArray("balance_updates").EnumerateArray(); + + if (balanceUpdates.Count() % 2 != 0) + throw new ValidationException("invalid vdf revelation balance updates count"); + + if (balanceUpdates.Any(x => + x.RequiredString("kind") == "contract" && Proposer != x.RequiredString("contract") || + x.RequiredString("kind") == "freezer" && Proposer != ( + x.Required("staker").Optional("baker_own_stake")?.GetString() + ?? x.Required("staker").Optional("baker_edge")?.GetString() + ?? x.Required("staker").Required("delegate").GetString() + ))) + throw new ValidationException("invalid vdf revelation baker"); + } + + protected virtual void ValidateDrainDelegate(JsonElement content) + { + var drainedBaker = content.RequiredString("delegate"); + var balanceUpdates = content.Required("metadata").RequiredArray("balance_updates").EnumerateArray(); + + if (!Cache.Accounts.DelegateExists(drainedBaker)) + throw new ValidationException("unknown drained delegate"); + + if (balanceUpdates.Count() % 2 != 0) + throw new ValidationException("invalid drain balance updates count"); + + if (balanceUpdates.Where(x => x.RequiredInt64("change") < 0).Any(x => x.RequiredString("contract") != drainedBaker)) + throw new ValidationException("invalid drain balance updates"); + } + + protected virtual async Task ValidateDelegation(JsonElement content) + { + var source = content.RequiredString("source"); + var delegat = content.OptionalString("delegate"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + if (content.Required("metadata").Required("operation_result").RequiredString("status") == "applied" && delegat != null) + if (source != delegat && !Cache.Accounts.DelegateExists(delegat)) + throw new ValidationException("unknown delegate account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + } + + protected virtual void ValidateInternalDelegation(JsonElement content, string initiator) + { + //var delegat = content.OptionalString("delegate"); + + //if (content.Required("result").RequiredString("status") == "applied" && delegat != null) + // if (!Cache.Accounts.DelegateExists(delegat)) + // throw new ValidationException("unknown delegate account"); + } + + protected virtual async Task ValidateOrigination(JsonElement content) + { + var source = content.RequiredString("source"); + var delegat = content.OptionalString("delegate"); + var metadata = content.Required("metadata"); + var result = metadata.Required("operation_result"); + var applied = result.RequiredString("status") == "applied"; + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + if (applied && delegat != null) + if (!Cache.Accounts.DelegateExists(delegat)) + throw new ValidationException("unknown delegate account"); + + ValidateFeeBalanceUpdates( + metadata.OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + if (applied && result.TryGetProperty("balance_updates", out var resultUpdates)) + ValidateTransferBalanceUpdates( + resultUpdates.EnumerateArray(), + source, + result.RequiredArray("originated_contracts", 1)[0].RequiredString(), + content.RequiredInt64("balance"), + (result.OptionalInt32("paid_storage_size_diff") ?? 0) * Protocol.ByteCost, + Protocol.OriginationSize * Protocol.ByteCost); + } + + protected virtual void ValidateInternalOrigination(JsonElement content, string initiator) + { + //var delegat = content.OptionalString("delegate"); + var result = content.Required("result"); + var applied = result.RequiredString("status") == "applied"; + + //if (applied && delegat != null) + // if (!Cache.Accounts.DelegateExists(delegat)) + // throw new ValidationException("unknown delegate account"); + + if (applied && result.TryGetProperty("balance_updates", out var resultUpdates)) + ValidateTransferBalanceUpdates( + resultUpdates.RequiredArray().EnumerateArray(), + content.RequiredString("source"), + result.RequiredArray("originated_contracts", 1)[0].RequiredString(), + content.RequiredInt64("balance"), + (result.OptionalInt32("paid_storage_size_diff") ?? 0) * Protocol.ByteCost, + Protocol.OriginationSize * Protocol.ByteCost, + initiator); + } + + protected virtual async Task ValidateTransaction(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + var metadata = content.Required("metadata"); + + ValidateFeeBalanceUpdates( + metadata.OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = metadata.Required("operation_result"); + var applied = result.RequiredString("status") == "applied"; + + if (applied) + { + var target = content.RequiredString("destination"); + + if (source == target && source.StartsWith("tz") && content.Optional("parameters")?.RequiredString("entrypoint") is string entrypoint) + { + switch (entrypoint) + { + case "stake": + case "unstake": + case "finalize_unstake": + case "set_delegate_parameters": + return; + default: + throw new ValidationException("unsupported staking operation"); + } + } + + if (result.TryGetProperty("balance_updates", out var resultUpdates)) + ValidateTransferBalanceUpdates( + resultUpdates.RequiredArray().EnumerateArray(), + source, + target, + content.RequiredInt64("amount"), + (result.OptionalInt32("paid_storage_size_diff") ?? 0) * Protocol.ByteCost, + (result.OptionalBool("allocated_destination_contract") ?? false) ? Protocol.OriginationSize * Protocol.ByteCost : 0); + } + + if (metadata.TryGetProperty("internal_operation_results", out var internalResults)) + { + foreach (var internalContent in internalResults.RequiredArray().EnumerateArray()) + { + switch (internalContent.RequiredString("kind")) + { + case "delegation": ValidateInternalDelegation(internalContent, source); break; + case "origination": ValidateInternalOrigination(internalContent, source); break; + case "transaction": ValidateInternalTransaction(internalContent, source); break; + case "event": break; + default: + throw new ValidationException("invalid internal operation kind"); + } + } + } + } + + protected virtual void ValidateInternalTransaction(JsonElement content, string initiator) + { + var result = content.Required("result"); + var applied = result.RequiredString("status") == "applied"; + + if (applied && result.TryGetProperty("balance_updates", out var resultUpdates)) + ValidateTransferBalanceUpdates( + resultUpdates.RequiredArray().EnumerateArray(), + content.RequiredString("source"), + content.RequiredString("destination"), + content.RequiredInt64("amount"), + (result.OptionalInt32("paid_storage_size_diff") ?? 0) * Protocol.ByteCost, + (result.OptionalBool("allocated_destination_contract") ?? false) ? Protocol.OriginationSize * Protocol.ByteCost : 0, + initiator); + } + + protected virtual async Task ValidateReveal(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + } + + protected virtual async Task ValidateDalPublishCommitment(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + } + + protected virtual async Task ValidateRegisterConstant(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + } + + protected virtual async Task ValidateSetDepositsLimit(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + } + + protected virtual async Task ValidateIncreasePaidStorage(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + } + + protected virtual async Task ValidateUpdateConsensusKey(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + } + + protected virtual async Task ValidateTxRollupOrigination(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = content.Required("metadata").Required("operation_result"); + var applied = result.RequiredString("status") == "applied"; + + if (applied && result.TryGetProperty("balance_updates", out var resultUpdates)) + ValidateTransferBalanceUpdates( + resultUpdates.EnumerateArray(), + source, + null, + 0, + 0, + 4_000 * Protocol.ByteCost); + } + + protected virtual async Task ValidateTxRollupSubmitBatch(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = content.Required("metadata").Required("operation_result"); + var applied = result.RequiredString("status") == "applied"; + + if (applied && result.TryGetProperty("balance_updates", out var resultUpdates)) + ValidateTransferBalanceUpdates( + resultUpdates.EnumerateArray(), + source, + null, + 0, + (result.OptionalInt32("paid_storage_size_diff") ?? 0) * Protocol.ByteCost, + 0); + } + + protected virtual async Task ValidateTxRollupCommit(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = content.Required("metadata").Required("operation_result"); + if (result.TryGetProperty("balance_updates", out var updates) && updates.Count() != 0) + { + if (updates.Count() != 2) + throw new ValidationException("unexpected number of rollup bonds balance updates"); + + if (!updates.EnumerateArray().Any(x => + x.RequiredString("kind") == "contract" && + x.RequiredString("contract") == source)) + throw new ValidationException("invalid transfer balance updates"); + + if (!updates.EnumerateArray().Any(x => + x.RequiredString("kind") == "freezer" && + x.RequiredString("category") == "bonds" && + x.RequiredString("contract") == source)) + throw new ValidationException("invalid transfer balance updates"); + + if (updates[0].RequiredInt64("change") != -updates[1].RequiredInt64("change")) + throw new ValidationException("inconsistent change of rollup bonds balance updates"); + } + } + + protected virtual async Task ValidateTxRollupFinalizeCommitment(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = content.Required("metadata").Required("operation_result"); + if (result.TryGetProperty("balance_updates", out var updates) && updates.Count() != 0) + throw new ValidationException("unexpected balance updates"); + } + + protected virtual async Task ValidateTxRollupRemoveCommitment(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = content.Required("metadata").Required("operation_result"); + if (result.TryGetProperty("balance_updates", out var updates) && updates.Count() != 0) + throw new ValidationException("unexpected balance updates"); + } + + protected virtual async Task ValidateTxRollupReturnBond(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = content.Required("metadata").Required("operation_result"); + if (result.TryGetProperty("balance_updates", out var updates) && updates.Count() != 0) + { + if (updates.Count() != 2) + throw new ValidationException("unexpected number of rollup bonds balance updates"); + + if (!updates.EnumerateArray().Any(x => + x.RequiredString("kind") == "contract" && + x.RequiredString("contract") == source)) + throw new ValidationException("invalid transfer balance updates"); + + if (!updates.EnumerateArray().Any(x => + x.RequiredString("kind") == "freezer" && + x.RequiredString("category") == "bonds" && + x.RequiredString("contract") == source)) + throw new ValidationException("invalid transfer balance updates"); + + if (updates[0].RequiredInt64("change") != -updates[1].RequiredInt64("change")) + throw new ValidationException("inconsistent change of rollup bonds balance updates"); + } + } + + protected virtual async Task ValidateTxRollupRejection(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + } + + protected virtual async Task ValidateTxRollupDispatchTickets(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + } + + protected virtual async Task ValidateTransferTicket(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + } + + protected virtual async Task ValidateSmartRollupAddMessages(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = content.Required("metadata").Required("operation_result"); + var applied = result.RequiredString("status") == "applied"; + + if (applied && result.TryGetProperty("balance_updates", out var resultUpdates)) + ValidateTransferBalanceUpdates( + resultUpdates.EnumerateArray(), + source, + null, + 0, + 0, + 0); + } + + protected virtual async Task ValidateSmartRollupCement(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = content.Required("metadata").Required("operation_result"); + if (result.RequiredString("status") == "applied" && + result.TryGetProperty("balance_updates", out var updates) && updates.Count() > 0) + throw new ValidationException("unexpected balnce updates"); + } + + protected virtual async Task ValidateSmartRollupExecute(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + var metadata = content.Required("metadata"); + + ValidateFeeBalanceUpdates( + metadata.OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = metadata.Required("operation_result"); + var applied = result.RequiredString("status") == "applied"; + + if (applied && result.TryGetProperty("balance_updates", out var resultUpdates)) + ValidateTransferBalanceUpdates( + resultUpdates.RequiredArray().EnumerateArray(), + source, + null, + 0, + (result.OptionalInt32("paid_storage_size_diff") ?? 0) * Protocol.ByteCost, + 0); + + if (metadata.TryGetProperty("internal_operation_results", out var internalResults)) + { + foreach (var internalContent in internalResults.RequiredArray().EnumerateArray()) + { + switch (internalContent.RequiredString("kind")) + { + case "delegation": ValidateInternalDelegation(internalContent, source); break; + case "origination": ValidateInternalOrigination(internalContent, source); break; + case "transaction": ValidateInternalTransaction(internalContent, source); break; + case "event": break; + default: + throw new ValidationException("invalid internal operation kind"); + } + } + } + } + + protected virtual async Task ValidateSmartRollupOriginate(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = content.Required("metadata").Required("operation_result"); + var applied = result.RequiredString("status") == "applied"; + + if (applied && result.TryGetProperty("balance_updates", out var resultUpdates)) + ValidateTransferBalanceUpdates( + resultUpdates.EnumerateArray(), + source, + null, + 0, + (result.OptionalInt32("size") ?? 0) * Protocol.ByteCost, + 0); + } + + protected virtual async Task ValidateSmartRollupPublish(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = content.Required("metadata").Required("operation_result"); + if (result.TryGetProperty("balance_updates", out var updates) && updates.Count() != 0) + { + if (updates.Count() != 2) + throw new ValidationException("unexpected number of smart rollup bonds balance updates"); + + if (!updates.EnumerateArray().Any(x => + x.RequiredString("kind") == "contract" && + x.RequiredString("contract") == source)) + throw new ValidationException("invalid smart rollup bonds balance updates"); + + if (!updates.EnumerateArray().Any(x => + x.RequiredString("kind") == "freezer" && + x.RequiredString("category") == "bonds" && + x.RequiredString("contract") == source)) + throw new ValidationException("invalid smart rollup bonds balance updates"); + + if (updates[0].RequiredInt64("change") != -updates[1].RequiredInt64("change")) + throw new ValidationException("inconsistent change of smart rollup bonds balance updates"); + } + } + + protected virtual async Task ValidateSmartRollupRecoverBond(JsonElement content) + { + var source = content.RequiredString("source"); + var staker = content.RequiredString("staker"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + + var result = content.Required("metadata").Required("operation_result"); + if (result.TryGetProperty("balance_updates", out var updates) && updates.Count() != 0) + { + if (updates.Count() != 2) + throw new ValidationException("unexpected number of smart rollup bonds balance updates"); + + if (!updates.EnumerateArray().Any(x => + x.RequiredString("kind") == "contract" && + x.RequiredString("contract") == staker)) + throw new ValidationException("invalid smart rollup bonds balance updates"); + + if (!updates.EnumerateArray().Any(x => + x.RequiredString("kind") == "freezer" && + x.RequiredString("category") == "bonds" && + x.RequiredString("contract") == staker)) + throw new ValidationException("invalid smart rollup bonds balance updates"); + + if (updates[0].RequiredInt64("change") != -updates[1].RequiredInt64("change")) + throw new ValidationException("inconsistent change of smart rollup bonds balance updates"); + } + } + + protected virtual async Task ValidateSmartRollupRefute(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + } + + protected virtual async Task ValidateSmartRollupTimeout(JsonElement content) + { + var source = content.RequiredString("source"); + + if (!await Cache.Accounts.ExistsAsync(source)) + throw new ValidationException("unknown source account"); + + ValidateFeeBalanceUpdates( + content.Required("metadata").OptionalArray("balance_updates")?.EnumerateArray() ?? Enumerable.Empty(), + source, + content.RequiredInt64("fee")); + } + + protected virtual void ValidateFeeBalanceUpdates(IEnumerable balanceUpdates, string sender, long fee) + { + if (fee != 0) + { + if (balanceUpdates.Count() != 2) + throw new ValidationException("invalid fee balance updates count"); + + var first = balanceUpdates.First(); + var last = balanceUpdates.Last(); + + if (first.RequiredString("kind") != "contract" || + first.RequiredString("contract") != sender || + first.RequiredInt64("change") != -fee) + throw new ValidationException("invalid fee contract update"); + + if (last.RequiredString("kind") != "accumulator" || + last.RequiredString("category") != "block fees" || + last.RequiredInt64("change") != fee) + throw new ValidationException("invalid fee accumulator update"); + } + else + { + if (balanceUpdates.Any()) + throw new ValidationException("invalid fee balance updates count"); + } + } + + protected virtual void ValidateTransferBalanceUpdates(IEnumerable balanceUpdates, string sender, string target, long amount, long storageFee, long allocationFee, string initiator = null) + { + if (balanceUpdates.Count() != (amount != 0 ? 2 : 0) + (storageFee != 0 ? 2 : 0) + (allocationFee != 0 ? 2 : 0)) + throw new ValidationException("invalid transfer balance updates count"); + + if (amount > 0) + { + if (!balanceUpdates.Any(x => + x.RequiredString("kind") == "contract" && + x.RequiredInt64("change") == -amount && + x.RequiredString("contract") == sender)) + throw new ValidationException("invalid transfer balance updates"); + + if (!balanceUpdates.Any(x => + x.RequiredString("kind") == "contract" && + x.RequiredInt64("change") == amount && + x.RequiredString("contract") == target)) + throw new ValidationException("invalid transfer balance updates"); + } + + if (storageFee > 0) + { + if (!balanceUpdates.Any(x => + x.RequiredString("kind") == "contract" && + x.RequiredInt64("change") == -storageFee && + x.RequiredString("contract") == (initiator ?? sender))) + throw new ValidationException("invalid storage fee balance updates"); + + if (!balanceUpdates.Any(x => + x.RequiredString("kind") == "burned" && + x.RequiredString("category") == "storage fees" && + x.RequiredInt64("change") == storageFee)) + throw new ValidationException("invalid storage fee balance updates"); + } + + if (allocationFee > 0) + { + if (!balanceUpdates.Any(x => + x.RequiredString("kind") == "contract" && + x.RequiredInt64("change") == -allocationFee && + x.RequiredString("contract") == (initiator ?? sender))) + throw new ValidationException("invalid allocation fee balance updates"); + + if (!balanceUpdates.Any(x => + x.RequiredString("kind") == "burned" && + x.RequiredString("category") == "storage fees" && + x.RequiredInt64("change") == allocationFee)) + throw new ValidationException("invalid allocation fee balance updates"); + } + } + } +} diff --git a/Tzkt.Sync/Protocols/Helpers/Chains.cs b/Tzkt.Sync/Protocols/Helpers/Chains.cs index c506f323f..475b38b27 100644 --- a/Tzkt.Sync/Protocols/Helpers/Chains.cs +++ b/Tzkt.Sync/Protocols/Helpers/Chains.cs @@ -18,6 +18,7 @@ static class Chains "NetXyuzvDo2Ugzb" => "nairobinet", "NetXxWsskGahzQB" => "oxfordnet", "NetXXWAHLEvre9b" => "parisnet", + "NetXyNQFuy15fmq" => "betanet", _ => "private" }; } diff --git a/Tzkt.Sync/Protocols/TezosProtocols.cs b/Tzkt.Sync/Protocols/TezosProtocols.cs index 594164d76..cf74d19c3 100644 --- a/Tzkt.Sync/Protocols/TezosProtocols.cs +++ b/Tzkt.Sync/Protocols/TezosProtocols.cs @@ -35,6 +35,7 @@ public static void AddTezosProtocols(this IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); } public static ProtocolHandler GetProtocolHandler(this IServiceProvider services, int level, string protocol) @@ -93,6 +94,7 @@ private static ProtocolHandler GetProtocolHandler(IServiceProvider services, str "PtParisBQscdCm6Cfow6ndeU6wKJyA3aV1j4D3gQBQMsTQyJCrz" => services.GetRequiredService(), "PtParisBxoLz5gzMmn3d9WBQNoPSZakgnkMC2VNuQ3KXfUtUQeZ" => services.GetRequiredService(), "PsParisCZo7KAh1Z1smVd9ZMZ1HHn5gkzbM94V3PLCpknFWhUAi" => services.GetRequiredService(), + "PtA4NFGxa5mLmPaEAAxAofESvLzZPSJ6GQz66SobecGbnCy3FXE" => services.GetRequiredService(), _ => null, }; } From 32fb238d5432212f9f24f57529be1f4738a1b239 Mon Sep 17 00:00:00 2001 From: 257Byte <257byte@gmail.com> Date: Fri, 30 Aug 2024 18:40:04 +0300 Subject: [PATCH 2/3] Add BetaA --- Tzkt.Sync/Protocols/Helpers/Chains.cs | 1 + Tzkt.Sync/Protocols/TezosProtocols.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/Tzkt.Sync/Protocols/Helpers/Chains.cs b/Tzkt.Sync/Protocols/Helpers/Chains.cs index 475b38b27..246ddc637 100644 --- a/Tzkt.Sync/Protocols/Helpers/Chains.cs +++ b/Tzkt.Sync/Protocols/Helpers/Chains.cs @@ -19,6 +19,7 @@ static class Chains "NetXxWsskGahzQB" => "oxfordnet", "NetXXWAHLEvre9b" => "parisnet", "NetXyNQFuy15fmq" => "betanet", + "NetXsTfFgyGbHTz" => "betanet", _ => "private" }; } diff --git a/Tzkt.Sync/Protocols/TezosProtocols.cs b/Tzkt.Sync/Protocols/TezosProtocols.cs index cf74d19c3..cd3d29f95 100644 --- a/Tzkt.Sync/Protocols/TezosProtocols.cs +++ b/Tzkt.Sync/Protocols/TezosProtocols.cs @@ -95,6 +95,7 @@ private static ProtocolHandler GetProtocolHandler(IServiceProvider services, str "PtParisBxoLz5gzMmn3d9WBQNoPSZakgnkMC2VNuQ3KXfUtUQeZ" => services.GetRequiredService(), "PsParisCZo7KAh1Z1smVd9ZMZ1HHn5gkzbM94V3PLCpknFWhUAi" => services.GetRequiredService(), "PtA4NFGxa5mLmPaEAAxAofESvLzZPSJ6GQz66SobecGbnCy3FXE" => services.GetRequiredService(), + "PtBetaaEZxGcn9JDpkpAZ6E92Kh7bQb5FDoTCeYhmkfcwNehZcT" => services.GetRequiredService(), _ => null, }; } From a8b07b60b78635ae4e891ea6ad89c5e66890883f Mon Sep 17 00:00:00 2001 From: Maksim Strebkov <257byte@gmail.com> Date: Wed, 13 Nov 2024 13:29:55 +0300 Subject: [PATCH 3/3] Add quebecnet --- .../Protocols/Handlers/Proto21/Activation/ProtoActivator.cs | 2 ++ Tzkt.Sync/Protocols/Handlers/Proto21/Proto21Handler.cs | 2 +- Tzkt.Sync/Protocols/Helpers/Chains.cs | 3 +-- Tzkt.Sync/Protocols/TezosProtocols.cs | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Activation/ProtoActivator.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Activation/ProtoActivator.cs index adc5f08d7..221cfdcd5 100644 --- a/Tzkt.Sync/Protocols/Handlers/Proto21/Activation/ProtoActivator.cs +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Activation/ProtoActivator.cs @@ -22,6 +22,8 @@ protected override void UpgradeParameters(Protocol protocol, Protocol prev) protocol.SmartRollupChallengeWindow = prev.SmartRollupChallengeWindow * 5 / 4; protocol.SmartRollupTimeoutPeriod = prev.SmartRollupTimeoutPeriod * 5 / 4; protocol.BlocksPerSnapshot = protocol.BlocksPerCycle; + protocol.MaxExternalOverOwnStakeRatio = 9; + protocol.StakePowerMultiplier = 3; } } diff --git a/Tzkt.Sync/Protocols/Handlers/Proto21/Proto21Handler.cs b/Tzkt.Sync/Protocols/Handlers/Proto21/Proto21Handler.cs index 1a3c2167c..086bcdbf3 100644 --- a/Tzkt.Sync/Protocols/Handlers/Proto21/Proto21Handler.cs +++ b/Tzkt.Sync/Protocols/Handlers/Proto21/Proto21Handler.cs @@ -14,7 +14,7 @@ class Proto21Handler : ProtocolHandler public override IDiagnostics Diagnostics { get; } public override IValidator Validator { get; } public override IRpc Rpc { get; } - public override string VersionName => "beta"; + public override string VersionName => "quebec_021"; public override int VersionNumber => 21; public Proto21Handler(TezosNode node, TzktContext db, CacheService cache, QuotesService quotes, IServiceProvider services, IConfiguration config, ILogger logger, IMetrics metrics) diff --git a/Tzkt.Sync/Protocols/Helpers/Chains.cs b/Tzkt.Sync/Protocols/Helpers/Chains.cs index 246ddc637..4c88d2b7e 100644 --- a/Tzkt.Sync/Protocols/Helpers/Chains.cs +++ b/Tzkt.Sync/Protocols/Helpers/Chains.cs @@ -18,8 +18,7 @@ static class Chains "NetXyuzvDo2Ugzb" => "nairobinet", "NetXxWsskGahzQB" => "oxfordnet", "NetXXWAHLEvre9b" => "parisnet", - "NetXyNQFuy15fmq" => "betanet", - "NetXsTfFgyGbHTz" => "betanet", + "NetXuTeGinLEqxp" => "quebecnet", _ => "private" }; } diff --git a/Tzkt.Sync/Protocols/TezosProtocols.cs b/Tzkt.Sync/Protocols/TezosProtocols.cs index cd3d29f95..2ed7994cd 100644 --- a/Tzkt.Sync/Protocols/TezosProtocols.cs +++ b/Tzkt.Sync/Protocols/TezosProtocols.cs @@ -95,7 +95,7 @@ private static ProtocolHandler GetProtocolHandler(IServiceProvider services, str "PtParisBxoLz5gzMmn3d9WBQNoPSZakgnkMC2VNuQ3KXfUtUQeZ" => services.GetRequiredService(), "PsParisCZo7KAh1Z1smVd9ZMZ1HHn5gkzbM94V3PLCpknFWhUAi" => services.GetRequiredService(), "PtA4NFGxa5mLmPaEAAxAofESvLzZPSJ6GQz66SobecGbnCy3FXE" => services.GetRequiredService(), - "PtBetaaEZxGcn9JDpkpAZ6E92Kh7bQb5FDoTCeYhmkfcwNehZcT" => services.GetRequiredService(), + "PsQuebecnLByd3JwTiGadoG4nGWi3HYiLXUjkibeFV8dCFeVMUg" => services.GetRequiredService(), _ => null, }; }