Task <Data.Models.Delegate> UpgradeUser(User user, int level, Protocol proto) { var delegat = new Data.Models.Delegate { ActivationLevel = level, Address = user.Address, FirstLevel = user.FirstLevel, LastLevel = user.LastLevel, Balance = user.Balance, Counter = user.Counter, DeactivationLevel = GracePeriod.Init(level, proto.BlocksPerCycle, proto.PreservedCycles), Delegate = null, DelegateId = null, DelegationLevel = null, Id = user.Id, Activated = user.Activated, DelegationsCount = user.DelegationsCount, OriginationsCount = user.OriginationsCount, TransactionsCount = user.TransactionsCount, RevealsCount = user.RevealsCount, ContractsCount = user.ContractsCount, MigrationsCount = user.MigrationsCount, PublicKey = user.PublicKey, Revealed = user.Revealed, Staked = true, StakingBalance = user.Balance, Type = AccountType.Delegate, }; Db.Entry(user).State = EntityState.Detached; Db.Entry(delegat).State = EntityState.Modified; Cache.Accounts.Add(delegat); return(Task.FromResult(delegat)); }
public override Task Apply() { #region entities var proto = Block.Protocol; var baker = Block.Baker; Db.TryAttach(proto); Db.TryAttach(baker); #endregion baker.Balance += Block.Reward; baker.FrozenRewards += Block.Reward; baker.FrozenDeposits += Block.Protocol.BlockDeposit; baker.BlocksCount++; var newDeactivationLevel = baker.Staked ? GracePeriod.Reset(Block) : GracePeriod.Init(Block); if (baker.DeactivationLevel < newDeactivationLevel) { Block.ResetDeactivation = baker.DeactivationLevel; baker.DeactivationLevel = newDeactivationLevel; } if (Block.Events.HasFlag(BlockEvents.ProtocolEnd)) { proto.LastLevel = Block.Level; } Db.Blocks.Add(Block); Cache.Blocks.Add(Block); return(Task.CompletedTask); }
public override async Task Apply() { #region entities var block = Endorsement.Block; var sender = Endorsement.Delegate; //Db.TryAttach(block); Db.TryAttach(sender); #endregion #region apply operation sender.Balance += Endorsement.Reward; sender.FrozenRewards += Endorsement.Reward; sender.FrozenDeposits += block.Protocol.EndorsementDeposit * Endorsement.Slots; sender.EndorsementsCount++; block.Operations |= Operations.Endorsements; block.Validations += Endorsement.Slots; var newDeactivationLevel = sender.Staked ? GracePeriod.Reset(Endorsement.Block) : GracePeriod.Init(Endorsement.Block); if (sender.DeactivationLevel < newDeactivationLevel) { if (sender.DeactivationLevel <= Endorsement.Level) { await UpdateDelegate(sender, true); } Endorsement.ResetDeactivation = sender.DeactivationLevel; sender.DeactivationLevel = newDeactivationLevel; } #endregion Db.EndorsementOps.Add(Endorsement); }
public async Task Init(Block block, RawBlock rawBlock) { var protocol = await Cache.Protocols.GetAsync(rawBlock.Protocol); BootstrapedAccounts = new List <Account>(65); Timestamp = rawBlock.Header.Timestamp; Level = rawBlock.Level; Block = block; var stream = await Proto.Node.GetContractsAsync(level : 1); var contracts = await(Proto.Serializer as Serializer).DeserializeContracts(stream); var delegates = new List <Data.Models.Delegate>(8); #region bootstrap delegates foreach (var data in contracts.Where(x => x.Delegate == x.Address)) { var baker = new Data.Models.Delegate { Id = Cache.AppState.NextAccountId(), Address = data.Address, FirstLevel = rawBlock.Level, LastLevel = rawBlock.Level, ActivationLevel = 1, DeactivationLevel = GracePeriod.Init(1, protocol.BlocksPerCycle, protocol.PreservedCycles), Balance = data.Balance, Counter = data.Counter, PublicKey = data.Manager, Staked = true, Revealed = true, Type = AccountType.Delegate }; Cache.Accounts.Add(baker); BootstrapedAccounts.Add(baker); delegates.Add(baker); } #endregion #region bootstrap users foreach (var data in contracts.Where(x => x.Address[0] == 't' && String.IsNullOrEmpty(x.Delegate))) { var user = new User { Id = Cache.AppState.NextAccountId(), Address = data.Address, FirstLevel = rawBlock.Level, LastLevel = rawBlock.Level, Balance = data.Balance, Counter = data.Counter, Type = AccountType.User }; Cache.Accounts.Add(user); BootstrapedAccounts.Add(user); } #endregion #region bootstrap contracts foreach (var data in contracts.Where(x => x.Address[0] == 'K')) { var manager = (User)await Cache.Accounts.GetAsync(data.Manager); manager.ContractsCount++; var contract = new Contract { Id = Cache.AppState.NextAccountId(), Address = data.Address, FirstLevel = rawBlock.Level, LastLevel = rawBlock.Level, Balance = data.Balance, Counter = data.Counter, Spendable = false, DelegationLevel = 1, Delegate = Cache.Accounts.GetDelegate(data.Delegate), Manager = manager, Staked = !String.IsNullOrEmpty(data.Delegate), Type = AccountType.Contract, Kind = ContractKind.SmartContract, }; Cache.Accounts.Add(contract); BootstrapedAccounts.Add(contract); } #endregion #region stats foreach (var baker in delegates) { var delegators = BootstrapedAccounts.Where(x => x.Delegate == baker); baker.DelegatorsCount = delegators.Count(); baker.StakingBalance = baker.Balance + (baker.DelegatorsCount > 0 ? delegators.Sum(x => x.Balance) : 0); } #endregion }
public virtual async Task Apply(JsonElement rawBlock) { var level = rawBlock.Required("header").RequiredInt32("level"); var protocol = await Cache.Protocols.GetAsync(rawBlock.RequiredString("protocol")); var events = BlockEvents.None; var metadata = rawBlock.Required("metadata"); var reward = GetBlockReward(metadata); var deposit = GetBlockDeposit(metadata); if (level % protocol.BlocksPerCycle == 1) { events |= BlockEvents.CycleBegin; } else if (level % protocol.BlocksPerCycle == 0) { events |= BlockEvents.CycleEnd; } if (protocol.FirstLevel == level) { events |= BlockEvents.ProtocolBegin; } else if (metadata.RequiredString("protocol") != metadata.RequiredString("next_protocol")) { events |= BlockEvents.ProtocolEnd; } if (metadata.RequiredArray("deactivated").Count() > 0) { events |= BlockEvents.Deactivations; } if (level % protocol.BlocksPerSnapshot == 0) { events |= BlockEvents.BalanceSnapshot; } Block = new Block { Id = Cache.AppState.NextOperationId(), Hash = rawBlock.RequiredString("hash"), Level = level, Protocol = protocol, Timestamp = rawBlock.Required("header").RequiredDateTime("timestamp"), Priority = rawBlock.Required("header").RequiredInt32("priority"), Baker = Cache.Accounts.GetDelegate(rawBlock.Required("metadata").RequiredString("baker")), Events = events, Reward = reward.ValueKind != JsonValueKind.Undefined ? reward.RequiredInt64("change") : 0, Deposit = deposit.ValueKind != JsonValueKind.Undefined ? deposit.RequiredInt64("change") : 0 }; #region entities var proto = Block.Protocol; var baker = Block.Baker; Db.TryAttach(proto); Db.TryAttach(baker); #endregion baker.Balance += Block.Reward; baker.FrozenRewards += Block.Reward; baker.FrozenDeposits += Block.Deposit; baker.BlocksCount++; var newDeactivationLevel = baker.Staked ? GracePeriod.Reset(Block) : GracePeriod.Init(Block); if (baker.DeactivationLevel < newDeactivationLevel) { if (baker.DeactivationLevel <= Block.Level) { await UpdateDelegate(baker, true); } Block.ResetDeactivation = baker.DeactivationLevel; baker.DeactivationLevel = newDeactivationLevel; } if (Block.Events.HasFlag(BlockEvents.ProtocolEnd)) { proto.LastLevel = Block.Level; } Db.Blocks.Add(Block); Cache.Blocks.Add(Block); }
public async Task Init(Block block, RawBlock rawBlock) { if (block.Events.HasFlag(BlockEvents.VotingPeriodEnd)) { Event = BlockEvents.VotingPeriodEnd; Period = await Cache.Periods.CurrentAsync(); Period.Epoch ??= await Db.VotingEpoches.FirstOrDefaultAsync(x => x.Id == Period.EpochId); } else if (block.Events.HasFlag(BlockEvents.VotingPeriodBegin)) { Event = BlockEvents.VotingPeriodBegin; var protocol = await Cache.Protocols.GetAsync(rawBlock.Protocol); var currentPeriod = await Cache.Periods.CurrentAsync(); var currentEpoch = await Db.VotingEpoches.FirstOrDefaultAsync(x => x.Id == currentPeriod.EpochId); if (rawBlock.Metadata.VotingPeriod == "proposal") { #region start proposal period Period = new ProposalPeriod { Code = currentPeriod.Code + 1, Epoch = new VotingEpoch { Level = rawBlock.Level }, Kind = VotingPeriods.Proposal, StartLevel = rawBlock.Level, EndLevel = rawBlock.Level + protocol.BlocksPerVoting - 1 }; #endregion } else if (rawBlock.Metadata.VotingPeriod == "testing_vote") { #region start exploration period var proposal = await Db.Proposals .Where(x => x.ProposalPeriodId == currentPeriod.Id) .OrderByDescending(x => x.Upvotes) .FirstAsync(); Cache.Proposals.Add(proposal); Period = new ExplorationPeriod { Code = currentPeriod.Code + 1, Epoch = currentEpoch, Kind = VotingPeriods.Exploration, StartLevel = rawBlock.Level, EndLevel = rawBlock.Level + protocol.BlocksPerVoting - 1, Proposal = proposal, ProposalId = proposal.Id }; #endregion } else if (rawBlock.Metadata.VotingPeriod == "testing") { #region start testing period Period = new TestingPeriod { Code = currentPeriod.Code + 1, Epoch = currentEpoch, Kind = VotingPeriods.Testing, StartLevel = rawBlock.Level, EndLevel = rawBlock.Level + protocol.BlocksPerVoting - 1, Proposal = await Cache.Proposals.GetAsync((currentPeriod as ExplorationPeriod).ProposalId), ProposalId = (currentPeriod as ExplorationPeriod).ProposalId }; #endregion } else if (rawBlock.Metadata.VotingPeriod == "promotion_vote") { #region start promotion period Period = new PromotionPeriod { Code = currentPeriod.Code + 1, Epoch = currentEpoch, Kind = VotingPeriods.Promotion, StartLevel = rawBlock.Level, EndLevel = rawBlock.Level + protocol.BlocksPerVoting - 1, Proposal = await Cache.Proposals.GetAsync((currentPeriod as TestingPeriod).ProposalId), ProposalId = (currentPeriod as TestingPeriod).ProposalId }; #endregion } else { throw new Exception("invalid voting period"); } if (!(Period is TestingPeriod)) { var gracePeriod = GracePeriod.Init(block); // TODO: fix crutch var delegates = await Db.Delegates .AsNoTracking() .Where(x => x.Staked && x.DeactivationLevel < gracePeriod && x.StakingBalance >= protocol.TokensPerRoll) .ToListAsync(); var lastBlock = await Cache.Blocks.CurrentAsync(); lastBlock.Protocol ??= await Cache.Protocols.GetAsync(lastBlock.ProtoCode); Rolls = new List <VotingSnapshot>(delegates.Count); foreach (var delegat in delegates) { Rolls.Add(new VotingSnapshot { Level = lastBlock.Level, Period = Period, DelegateId = delegat.Id, Rolls = (int)(delegat.StakingBalance / lastBlock.Protocol.TokensPerRoll) }); } if (Period is ExplorationPeriod exploration) { exploration.TotalStake = Rolls.Sum(x => x.Rolls); } else if (Period is PromotionPeriod promotion) { promotion.TotalStake = Rolls.Sum(x => x.Rolls); } } } }
public virtual async Task Apply(Block block, JsonElement op, JsonElement content) { #region init var metadata = content.Required("metadata"); var reward = metadata .RequiredArray("balance_updates") .EnumerateArray() .FirstOrDefault(x => x.RequiredString("kind")[0] == 'f' && x.RequiredString("category")[0] == 'r'); var deposit = metadata .RequiredArray("balance_updates") .EnumerateArray() .FirstOrDefault(x => x.RequiredString("kind")[0] == 'f' && x.RequiredString("category")[0] == 'd'); var endorsement = new EndorsementOperation { Id = Cache.AppState.NextOperationId(), Block = block, Level = block.Level, Timestamp = block.Timestamp, OpHash = op.RequiredString("hash"), Slots = metadata.RequiredArray("slots").Count(), Delegate = Cache.Accounts.GetDelegate(metadata.RequiredString("delegate")), Reward = reward.ValueKind != JsonValueKind.Undefined ? reward.RequiredInt64("change") : 0, Deposit = deposit.ValueKind != JsonValueKind.Undefined ? deposit.RequiredInt64("change") : 0 }; #endregion #region entities //var block = endorsement.Block; var sender = endorsement.Delegate; //Db.TryAttach(block); Db.TryAttach(sender); #endregion #region apply operation sender.Balance += endorsement.Reward; sender.FrozenRewards += endorsement.Reward; sender.FrozenDeposits += endorsement.Deposit; sender.EndorsementsCount++; block.Operations |= Operations.Endorsements; block.Validations += endorsement.Slots; var newDeactivationLevel = sender.Staked ? GracePeriod.Reset(endorsement.Block) : GracePeriod.Init(endorsement.Block); if (sender.DeactivationLevel < newDeactivationLevel) { if (sender.DeactivationLevel <= endorsement.Level) { await UpdateDelegate(sender, true); } endorsement.ResetDeactivation = sender.DeactivationLevel; sender.DeactivationLevel = newDeactivationLevel; } #endregion Db.EndorsementOps.Add(endorsement); }
async Task <List <Account> > BootstrapAccounts(Protocol protocol) { var rawAccounts = await Proto.Rpc.GetAllContractsAsync(1); var accounts = new List <Account>(65); #region bootstrap delegates foreach (var data in rawAccounts .EnumerateArray() .Where(x => x[0].RequiredString() == x[1].OptionalString("delegate"))) { var baker = new Delegate { Id = Cache.AppState.NextAccountId(), Address = data[0].RequiredString(), Balance = data[1].RequiredInt64("balance"), StakingBalance = data[1].RequiredInt64("balance"), Counter = data[1].RequiredInt32("counter"), PublicKey = data[1].RequiredString("manager"), FirstLevel = 1, LastLevel = 1, ActivationLevel = 1, DeactivationLevel = GracePeriod.Init(1, protocol.BlocksPerCycle, protocol.PreservedCycles), Staked = true, Revealed = true, Type = AccountType.Delegate }; Cache.Accounts.Add(baker); accounts.Add(baker); } #endregion #region bootstrap users foreach (var data in rawAccounts .EnumerateArray() .Where(x => x[0].RequiredString()[0] == 't' && x[1].OptionalString("delegate") == null)) { var user = new User { Id = Cache.AppState.NextAccountId(), Address = data[0].RequiredString(), Balance = data[1].RequiredInt64("balance"), Counter = data[1].RequiredInt32("counter"), FirstLevel = 1, LastLevel = 1, Type = AccountType.User }; Cache.Accounts.Add(user); accounts.Add(user); } #endregion #region bootstrap contracts foreach (var data in rawAccounts.EnumerateArray().Where(x => x[0].RequiredString()[0] == 'K')) { var delegat = Cache.Accounts.GetDelegate(data[1].OptionalString("delegate")); var manager = (User)await Cache.Accounts.GetAsync(data[1].RequiredString("manager")); var contract = new Contract { Id = Cache.AppState.NextAccountId(), Address = data[0].RequiredString(), Balance = data[1].RequiredInt64("balance"), Counter = data[1].RequiredInt32("counter"), FirstLevel = 1, LastLevel = 1, Spendable = false, DelegationLevel = 1, Delegate = delegat, Manager = manager, Staked = !string.IsNullOrEmpty(data[1].OptionalString("delegate")), Type = AccountType.Contract, Kind = ContractKind.SmartContract, }; #region script var code = Micheline.FromJson(data[1].Required("code")) as MichelineArray; var micheParameter = code.First(x => x is MichelinePrim p && p.Prim == PrimType.parameter); var micheStorage = code.First(x => x is MichelinePrim p && p.Prim == PrimType.storage); var micheCode = code.First(x => x is MichelinePrim p && p.Prim == PrimType.code); var script = new Script { ContractId = contract.Id, ParameterSchema = micheParameter.ToBytes(), StorageSchema = micheStorage.ToBytes(), CodeSchema = micheCode.ToBytes(), Current = true }; Db.Scripts.Add(script); Cache.Schemas.Add(contract, script.Schema); var storageValue = Micheline.FromJson(data[1].Required("storage")); var storage = new Storage { Level = 1, ContractId = contract.Id, RawValue = script.Schema.OptimizeStorage(storageValue, false).ToBytes(), JsonValue = script.Schema.HumanizeStorage(storageValue), Current = true }; Db.Storages.Add(storage); Cache.Storages.Add(contract, storage); #endregion manager.ContractsCount++; delegat.DelegatorsCount++; delegat.StakingBalance += contract.Balance; Cache.Accounts.Add(contract); accounts.Add(contract); } #endregion Db.Accounts.AddRange(accounts); #region migration ops var block = Cache.Blocks.Current(); block.Operations |= Operations.Migrations; if (accounts.Any(x => x.Type == AccountType.Contract)) { block.Events |= BlockEvents.SmartContracts; } foreach (var account in accounts) { var migration = new MigrationOperation { Id = Cache.AppState.NextOperationId(), Block = block, Level = block.Level, Timestamp = block.Timestamp, Account = account, Kind = MigrationKind.Bootstrap, BalanceChange = account.Balance, }; if (account is Contract contract) { var script = Db.ChangeTracker.Entries() .First(x => x.Entity is Script s && s.ContractId == contract.Id).Entity as Script; var storage = await Cache.Storages.GetAsync(contract); script.MigrationId = migration.Id; storage.MigrationId = migration.Id; migration.NewScript = script; migration.NewStorage = storage; } Db.MigrationOps.Add(migration); account.MigrationsCount++; } var state = Cache.AppState.Get(); state.MigrationOpsCount += accounts.Count; #endregion #region statistics var stats = await Cache.Statistics.GetAsync(1); stats.TotalBootstrapped = accounts.Sum(x => x.Balance); stats.TotalVested = accounts.Where(x => x.Type == AccountType.Contract).Sum(x => x.Balance); #endregion return(accounts); }
async Task <List <Account> > BootstrapAccounts(Protocol protocol, JToken parameters) { var bootstrapAccounts = parameters["bootstrap_accounts"]? .Select(x => (x[0].Value <string>(), x[1].Value <long>())) .ToList() ?? new(0); var bootstrapContracts = parameters["bootstrap_contracts"]? .Select(x => ( x["amount"].Value <long>(), x["delegate"]?.Value <string>() ?? null, x["script"]["code"].ToString(), x["script"]["storage"].ToString()) ) .ToList() ?? new(0); var accounts = new List <Account>(bootstrapAccounts.Count + bootstrapContracts.Count); #region allocate null-address var nullAddress = (User)await Cache.Accounts.GetAsync(NullAddress.Address); if (nullAddress.Id != NullAddress.Id) { throw new Exception("Failed to allocate null-address"); } #endregion #region bootstrap delegates foreach (var(pubKey, balance) in bootstrapAccounts.Where(x => x.Item1[0] != 't')) { var baker = new Data.Models.Delegate { Id = Cache.AppState.NextAccountId(), Address = PubKey.FromBase58(pubKey).Address, Balance = balance, StakingBalance = balance, Counter = 0, PublicKey = pubKey, FirstLevel = 1, LastLevel = 1, ActivationLevel = 1, DeactivationLevel = GracePeriod.Init(2, protocol), Staked = true, Revealed = true, Type = AccountType.Delegate }; Cache.Accounts.Add(baker); accounts.Add(baker); } #endregion #region bootstrap users foreach (var(pkh, balance) in bootstrapAccounts.Where(x => x.Item1[0] == 't')) { var user = new User { Id = Cache.AppState.NextAccountId(), Address = pkh, Balance = balance, Counter = 0, FirstLevel = 1, LastLevel = 1, Type = AccountType.User }; Cache.Accounts.Add(user); accounts.Add(user); } #endregion #region bootstrap contracts var index = 0; foreach (var(balance, delegatePkh, codeStr, storageStr) in bootstrapContracts) { #region contract var delegat = Cache.Accounts.GetDelegate(delegatePkh); var manager = nullAddress; var contract = new Contract { Id = Cache.AppState.NextAccountId(), Address = OriginationNonce.GetContractAddress(index++), Balance = balance, Counter = 0, FirstLevel = 1, LastLevel = 1, Spendable = false, DelegationLevel = delegat == null ? null : 1, Delegate = delegat, Manager = manager, Staked = delegat != null, Type = AccountType.Contract, Kind = ContractKind.SmartContract, }; manager.ContractsCount++; if (delegat != null) { delegat.DelegatorsCount++; delegat.StakingBalance += contract.Balance; } Cache.Accounts.Add(contract); accounts.Add(contract); #endregion #region script var code = Micheline.FromJson(codeStr) as MichelineArray; var micheParameter = code.First(x => x is MichelinePrim p && p.Prim == PrimType.parameter); var micheStorage = code.First(x => x is MichelinePrim p && p.Prim == PrimType.storage); var micheCode = code.First(x => x is MichelinePrim p && p.Prim == PrimType.code); var micheViews = code.Where(x => x is MichelinePrim p && p.Prim == PrimType.view); var script = new Script { Id = Cache.AppState.NextScriptId(), Level = 1, ContractId = contract.Id, ParameterSchema = micheParameter.ToBytes(), StorageSchema = micheStorage.ToBytes(), CodeSchema = micheCode.ToBytes(), Views = micheViews.Any() ? micheViews.Select(x => x.ToBytes()).ToArray() : null, Current = true }; var viewsBytes = script.Views? .OrderBy(x => x, new BytesComparer()) .SelectMany(x => x) .ToArray() ?? Array.Empty <byte>(); var typeSchema = script.ParameterSchema.Concat(script.StorageSchema).Concat(viewsBytes); var fullSchema = typeSchema.Concat(script.CodeSchema); contract.TypeHash = script.TypeHash = Script.GetHash(typeSchema); contract.CodeHash = script.CodeHash = Script.GetHash(fullSchema); if (script.Schema.IsFA1()) { if (script.Schema.IsFA12()) { contract.Tags |= ContractTags.FA12; } contract.Tags |= ContractTags.FA1; contract.Kind = ContractKind.Asset; } if (script.Schema.IsFA2()) { contract.Tags |= ContractTags.FA2; contract.Kind = ContractKind.Asset; } Db.Scripts.Add(script); Cache.Schemas.Add(contract, script.Schema); #endregion #region storage var storageValue = Micheline.FromJson(storageStr); var storage = new Storage { Id = Cache.AppState.NextStorageId(), Level = 1, ContractId = contract.Id, RawValue = script.Schema.OptimizeStorage(storageValue, false).ToBytes(), JsonValue = script.Schema.HumanizeStorage(storageValue), Current = true }; Db.Storages.Add(storage); Cache.Storages.Add(contract, storage); #endregion } #endregion Db.Accounts.AddRange(accounts); #region migration ops var block = Cache.Blocks.Current(); block.Operations |= Operations.Migrations; if (accounts.Any(x => x.Type == AccountType.Contract)) { block.Events |= BlockEvents.SmartContracts; } foreach (var account in accounts) { var migration = new MigrationOperation { Id = Cache.AppState.NextOperationId(), Block = block, Level = block.Level, Timestamp = block.Timestamp, Account = account, Kind = MigrationKind.Bootstrap, BalanceChange = account.Balance, }; if (account is Contract contract) { var script = Db.ChangeTracker.Entries() .First(x => x.Entity is Script s && s.ContractId == contract.Id).Entity as Script; var storage = await Cache.Storages.GetAsync(contract); script.MigrationId = migration.Id; storage.MigrationId = migration.Id; migration.Script = script; migration.Storage = storage; } Db.MigrationOps.Add(migration); account.MigrationsCount++; } var state = Cache.AppState.Get(); state.MigrationOpsCount += accounts.Count; #endregion #region statistics var stats = await Cache.Statistics.GetAsync(1); stats.TotalBootstrapped = accounts.Sum(x => x.Balance); stats.TotalVested = accounts.Where(x => x.Type == AccountType.Contract).Sum(x => x.Balance); #endregion return(accounts); }