User DowngradeDelegate(Data.Models.Delegate delegat) { var user = new User { Address = delegat.Address, FirstLevel = delegat.FirstLevel, LastLevel = delegat.LastLevel, Balance = delegat.Balance, Counter = delegat.Counter, Delegate = null, DelegateId = null, DelegationLevel = null, Id = delegat.Id, Activated = delegat.Activated, DelegationsCount = delegat.DelegationsCount, OriginationsCount = delegat.OriginationsCount, TransactionsCount = delegat.TransactionsCount, RevealsCount = delegat.RevealsCount, ContractsCount = delegat.ContractsCount, MigrationsCount = delegat.MigrationsCount, PublicKey = delegat.PublicKey, Revealed = delegat.Revealed, Staked = false, Type = AccountType.User, }; Db.Entry(delegat).State = EntityState.Detached; Db.Entry(user).State = EntityState.Modified; Cache.Accounts.Add(user); return(user); }
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)); }
protected virtual void TestDelegatorsCount(JsonElement remote, Data.Models.Delegate local) { if (remote.RequiredArray("delegated_contracts").Count() != local.DelegatorsCount) { throw new Exception($"Diagnostics failed: wrong delegators count {local.Address}"); } }
protected override void TestDelegatorsCount(JsonElement remote, Data.Models.Delegate local) { var delegators = remote.RequiredArray("delegated_contracts").Count(); if (delegators != local.DelegatorsCount && delegators != local.DelegatorsCount + 1) { throw new Exception($"Diagnostics failed: wrong delegators count {local.Address}"); } }
async Task UpdateDelegate(Data.Models.Delegate delegat, bool staked) { delegat.Staked = staked; foreach (var delegator in await Db.Accounts.Where(x => x.DelegateId == delegat.Id).ToListAsync()) { Cache.Accounts.Add(delegator); Db.TryAttach(delegator); delegator.Staked = staked; } }
protected virtual async Task TestDelegate(int level, Data.Models.Delegate delegat, Protocol proto) { var remote = await Rpc.GetDelegateAsync(level, delegat.Address); if (remote.RequiredInt64("balance") != delegat.Balance) { throw new Exception($"Diagnostics failed: wrong balance {delegat.Address}"); } if (remote.RequiredBool("deactivated") != !delegat.Staked) { throw new Exception($"Diagnostics failed: wrong delegate state {delegat.Address}"); } var deactivationCycle = (delegat.DeactivationLevel - 1) >= proto.FirstLevel ? proto.GetCycle(delegat.DeactivationLevel - 1) : (await Cache.Blocks.GetAsync(delegat.DeactivationLevel - 1)).Cycle; if (remote.RequiredInt32("grace_period") != deactivationCycle) { throw new Exception($"Diagnostics failed: wrong delegate grace period {delegat.Address}"); } if (remote.RequiredInt64("staking_balance") != delegat.StakingBalance) { throw new Exception($"Diagnostics failed: wrong staking balance {delegat.Address}"); } var frozenBalances = remote.RequiredArray("frozen_balance_by_cycle").EnumerateArray(); if ((frozenBalances.Any() ? frozenBalances.Sum(x => GetDeposits(x)) : 0) != delegat.FrozenDeposits) { throw new Exception($"Diagnostics failed: wrong frozen deposits {delegat.Address}"); } if ((frozenBalances.Any() ? frozenBalances.Sum(x => x.RequiredInt64("rewards")) : 0) != delegat.FrozenRewards) { throw new Exception($"Diagnostics failed: wrong frozen rewards {delegat.Address}"); } if ((frozenBalances.Any() ? frozenBalances.Sum(x => x.RequiredInt64("fees")) : 0) != delegat.FrozenFees) { throw new Exception($"Diagnostics failed: wrong frozen fees {delegat.Address}"); } TestDelegatorsCount(remote, delegat); }
async Task TestDelegate(int level, Data.Models.Delegate delegat, Protocol proto) { var remote = await GetRemoteDelegate(level, delegat.Address); if (remote.Balance != delegat.Balance) { throw new Exception($"Diagnostics failed: wrong balance {delegat.Address}"); } if (remote.Deactivated != !delegat.Staked) { throw new Exception($"Diagnostics failed: wrong delegate state {delegat.Address}"); } if (remote.GracePeriod != (delegat.DeactivationLevel - 2) / proto.BlocksPerCycle) { throw new Exception($"Diagnostics failed: wrong delegate grace period {delegat.Address}"); } if (remote.Delegators.Count != delegat.DelegatorsCount) { throw new Exception($"Diagnostics failed: wrong delegators count {delegat.Address}"); } if ((remote.FrozenBalances.Count > 0 ? remote.FrozenBalances.Sum(x => x.Deposit) : 0) != delegat.FrozenDeposits) { throw new Exception($"Diagnostics failed: wrong frozen deposits {delegat.Address}"); } if ((remote.FrozenBalances.Count > 0 ? remote.FrozenBalances.Sum(x => x.Fees) : 0) != delegat.FrozenFees) { throw new Exception($"Diagnostics failed: wrong frozen fees {delegat.Address}"); } if ((remote.FrozenBalances.Count > 0 ? remote.FrozenBalances.Sum(x => x.Rewards) : 0) != delegat.FrozenRewards) { throw new Exception($"Diagnostics failed: wrong frozen rewards {delegat.Address}"); } if (remote.StakingBalance != delegat.StakingBalance) { throw new Exception($"Diagnostics failed: wrong staking balance {delegat.Address}"); } }
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 }
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); }