Ejemplo n.º 1
0
        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));
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
0
        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
        }
Ejemplo n.º 5
0
        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);
        }
Ejemplo n.º 6
0
        public async Task Init(Block block, RawBlock rawBlock)
        {
            if (block.Events.HasFlag(BlockEvents.VotingPeriodEnd))
            {
                Event  = BlockEvents.VotingPeriodEnd;
                Period = await Cache.Periods.CurrentAsync();

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

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

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

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

                    Cache.Proposals.Add(proposal);

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

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

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

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

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

                    if (Period is ExplorationPeriod exploration)
                    {
                        exploration.TotalStake = Rolls.Sum(x => x.Rolls);
                    }
                    else if (Period is PromotionPeriod promotion)
                    {
                        promotion.TotalStake = Rolls.Sum(x => x.Rolls);
                    }
                }
            }
        }
Ejemplo n.º 7
0
        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);
        }
Ejemplo n.º 8
0
        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);
        }
Ejemplo n.º 9
0
        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);
        }