Ejemplo n.º 1
0
        private void Persist(Block block)
        {
            using (SnapshotView snapshot = GetSnapshot())
            {
                if (block.Index == header_index.Count)
                {
                    header_index.Add(block.Hash);
                    snapshot.HeaderHashIndex.GetAndChange().Set(block);
                }
                List <ApplicationExecuted> all_application_executed = new List <ApplicationExecuted>();
                snapshot.PersistingBlock = block;
                if (block.Index > 0)
                {
                    using (ApplicationEngine engine = new ApplicationEngine(TriggerType.System, null, snapshot, 0, true))
                    {
                        engine.LoadScript(onPersistNativeContractScript);
                        if (engine.Execute() != VMState.HALT)
                        {
                            throw new InvalidOperationException();
                        }
                        ApplicationExecuted application_executed = new ApplicationExecuted(engine);
                        Context.System.EventStream.Publish(application_executed);
                        all_application_executed.Add(application_executed);
                    }
                }
                snapshot.Blocks.Add(block.Hash, block.Trim());
                StoreView clonedSnapshot = snapshot.Clone();
                // Warning: Do not write into variable snapshot directly. Write into variable clonedSnapshot and commit instead.
                foreach (Transaction tx in block.Transactions)
                {
                    var state = new TransactionState
                    {
                        BlockIndex  = block.Index,
                        Transaction = tx
                    };

                    clonedSnapshot.Transactions.Add(tx.Hash, state);
                    clonedSnapshot.Transactions.Commit();

                    using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, tx, clonedSnapshot, tx.SystemFee))
                    {
                        engine.LoadScript(tx.Script);
                        state.VMState = engine.Execute();
                        if (state.VMState == VMState.HALT)
                        {
                            clonedSnapshot.Commit();
                        }
                        else
                        {
                            clonedSnapshot = snapshot.Clone();
                        }
                        ApplicationExecuted application_executed = new ApplicationExecuted(engine);
                        Context.System.EventStream.Publish(application_executed);
                        all_application_executed.Add(application_executed);
                    }
                }
                snapshot.BlockHashIndex.GetAndChange().Set(block);
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    plugin.OnPersist(snapshot, all_application_executed);
                }
                snapshot.Commit();
                List <Exception> commitExceptions = null;
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    try
                    {
                        plugin.OnCommit(snapshot);
                    }
                    catch (Exception ex)
                    {
                        if (plugin.ShouldThrowExceptionFromCommit(ex))
                        {
                            if (commitExceptions == null)
                            {
                                commitExceptions = new List <Exception>();
                            }

                            commitExceptions.Add(ex);
                        }
                    }
                }
                if (commitExceptions != null)
                {
                    throw new AggregateException(commitExceptions);
                }
            }
            UpdateCurrentSnapshot();
            block_cache.Remove(block.PrevHash);
            MemPool.UpdatePoolForBlockPersisted(block, currentSnapshot);
            Context.System.EventStream.Publish(new PersistCompleted {
                Block = block
            });
        }
Ejemplo n.º 2
0
        private void Persist(Block block)
        {
            WriteBatch batch = new WriteBatch();
            DbCache <UInt160, AccountState>        accounts         = new DbCache <UInt160, AccountState>(db, DataEntryPrefix.ST_Account, batch);
            DbCache <UInt256, UnspentCoinState>    unspentcoins     = new DbCache <UInt256, UnspentCoinState>(db, DataEntryPrefix.ST_Coin, batch);
            DbCache <UInt256, SpentCoinState>      spentcoins       = new DbCache <UInt256, SpentCoinState>(db, DataEntryPrefix.ST_SpentCoin, batch);
            DbCache <ECPoint, ValidatorState>      validators       = new DbCache <ECPoint, ValidatorState>(db, DataEntryPrefix.ST_Validator, batch);
            DbCache <UInt256, AssetState>          assets           = new DbCache <UInt256, AssetState>(db, DataEntryPrefix.ST_Asset, batch);
            DbCache <UInt160, ContractState>       contracts        = new DbCache <UInt160, ContractState>(db, DataEntryPrefix.ST_Contract, batch);
            DbCache <StorageKey, StorageItem>      storages         = new DbCache <StorageKey, StorageItem>(db, DataEntryPrefix.ST_Storage, batch);
            DbMetaDataCache <ValidatorsCountState> validators_count = new DbMetaDataCache <ValidatorsCountState>(db, DataEntryPrefix.IX_ValidatorsCount);
            long amount_sysfee = GetSysFeeAmount(block.PrevHash) + (long)block.Transactions.Sum(p => p.SystemFee);

            batch.Put(SliceBuilder.Begin(DataEntryPrefix.DATA_Block).Add(block.Hash), SliceBuilder.Begin().Add(amount_sysfee).Add(block.Trim()));
            foreach (Transaction tx in block.Transactions)
            {
                batch.Put(SliceBuilder.Begin(DataEntryPrefix.DATA_Transaction).Add(tx.Hash), SliceBuilder.Begin().Add(block.Index).Add(tx.ToArray()));
                unspentcoins.Add(tx.Hash, new UnspentCoinState
                {
                    Items = Enumerable.Repeat(CoinState.Confirmed, tx.Outputs.Length).ToArray()
                });
                foreach (TransactionOutput output in tx.Outputs)
                {
                    AccountState account = accounts.GetAndChange(output.ScriptHash, () => new AccountState(output.ScriptHash));
                    if (account.Balances.ContainsKey(output.AssetId))
                    {
                        account.Balances[output.AssetId] += output.Value;
                    }
                    else
                    {
                        account.Balances[output.AssetId] = output.Value;
                    }
                    if (output.AssetId.Equals(GoverningToken.Hash) && account.Votes.Length > 0)
                    {
                        foreach (ECPoint pubkey in account.Votes)
                        {
                            validators.GetAndChange(pubkey, () => new ValidatorState(pubkey)).Votes += output.Value;
                        }
                        validators_count.GetAndChange().Votes[account.Votes.Length - 1] += output.Value;
                    }
                }
                foreach (var group in tx.Inputs.GroupBy(p => p.PrevHash))
                {
                    Transaction tx_prev = GetTransaction(ReadOptions.Default, group.Key, out int height);
                    foreach (CoinReference input in group)
                    {
                        unspentcoins.GetAndChange(input.PrevHash).Items[input.PrevIndex] |= CoinState.Spent;
                        TransactionOutput out_prev = tx_prev.Outputs[input.PrevIndex];
                        AccountState      account  = accounts.GetAndChange(out_prev.ScriptHash);
                        if (out_prev.AssetId.Equals(GoverningToken.Hash))
                        {
                            spentcoins.GetAndChange(input.PrevHash, () => new SpentCoinState
                            {
                                TransactionHash   = input.PrevHash,
                                TransactionHeight = (uint)height,
                                Items             = new Dictionary <ushort, uint>()
                            }).Items.Add(input.PrevIndex, block.Index);
                            if (account.Votes.Length > 0)
                            {
                                foreach (ECPoint pubkey in account.Votes)
                                {
                                    ValidatorState validator = validators.GetAndChange(pubkey);
                                    validator.Votes -= out_prev.Value;
                                    if (!validator.Registered && validator.Votes.Equals(Fixed8.Zero))
                                    {
                                        validators.Delete(pubkey);
                                    }
                                }
                                validators_count.GetAndChange().Votes[account.Votes.Length - 1] -= out_prev.Value;
                            }
                        }
                        account.Balances[out_prev.AssetId] -= out_prev.Value;
                    }
                }
                switch (tx)
                {
#pragma warning disable CS0612
                case RegisterTransaction tx_register:
                    assets.Add(tx.Hash, new AssetState
                    {
                        AssetId    = tx_register.Hash,
                        AssetType  = tx_register.AssetType,
                        Name       = tx_register.Name,
                        Amount     = tx_register.Amount,
                        Available  = Fixed8.Zero,
                        Precision  = tx_register.Precision,
                        Fee        = Fixed8.Zero,
                        FeeAddress = new UInt160(),
                        Owner      = tx_register.Owner,
                        Admin      = tx_register.Admin,
                        Issuer     = tx_register.Admin,
                        Expiration = block.Index + 2 * 2000000,
                        IsFrozen   = false
                    });
                    break;

#pragma warning restore CS0612
                case IssueTransaction _:
                    foreach (TransactionResult result in tx.GetTransactionResults().Where(p => p.Amount < Fixed8.Zero))
                    {
                        assets.GetAndChange(result.AssetId).Available -= result.Amount;
                    }
                    break;

                case ClaimTransaction _:
                    foreach (CoinReference input in ((ClaimTransaction)tx).Claims)
                    {
                        if (spentcoins.TryGet(input.PrevHash)?.Items.Remove(input.PrevIndex) == true)
                        {
                            spentcoins.GetAndChange(input.PrevHash);
                        }
                    }
                    break;

#pragma warning disable CS0612
                case EnrollmentTransaction tx_enrollment:
                    validators.GetAndChange(tx_enrollment.PublicKey, () => new ValidatorState(tx_enrollment.PublicKey)).Registered = true;
                    break;

#pragma warning restore CS0612
                case StateTransaction tx_state:
                    foreach (StateDescriptor descriptor in tx_state.Descriptors)
                    {
                        switch (descriptor.Type)
                        {
                        case StateType.Account:
                            ProcessAccountStateDescriptor(descriptor, accounts, validators, validators_count);
                            break;

                        case StateType.Validator:
                            ProcessValidatorStateDescriptor(descriptor, validators);
                            break;
                        }
                    }
                    break;

#pragma warning disable CS0612
                case PublishTransaction tx_publish:
                    contracts.GetOrAdd(tx_publish.ScriptHash, () => new ContractState
                    {
                        Script             = tx_publish.Script,
                        ParameterList      = tx_publish.ParameterList,
                        ReturnType         = tx_publish.ReturnType,
                        ContractProperties = (ContractPropertyState)Convert.ToByte(tx_publish.NeedStorage),
                        Name        = tx_publish.Name,
                        CodeVersion = tx_publish.CodeVersion,
                        Author      = tx_publish.Author,
                        Email       = tx_publish.Email,
                        Description = tx_publish.Description
                    });
                    break;

#pragma warning restore CS0612
                case InvocationTransaction tx_invocation:
                    CachedScriptTable script_table = new CachedScriptTable(contracts);
                    using (StateMachine service = new StateMachine(block, accounts, assets, contracts, storages))
                    {
                        ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, tx_invocation, script_table, service, tx_invocation.Gas);
                        ///add log
                        bool bLog  = false;
                        var  split = block.Header.Index % this.fulllog_splitcount;
                        if (this.FullLogPath != null && split == this.fulllog_splitindex)        // && this.FullLogSkip.Contains(itx.Hash.ToString()) == false)
                        {
                            bLog = true;
                        }
                        if (bLog)
                        {
                            engine.BeginDebug();
                        }

                        engine.LoadScript(tx_invocation.Script, false);
                        if (engine.Execute())
                        {
                            service.Commit();
                        }
                        ApplicationExecuted?.Invoke(this, new ApplicationExecutedEventArgs(tx_invocation, service.Notifications.ToArray(), engine));
                        //write fulllog
                        if (bLog)
                        {
                            string filename = System.IO.Path.Combine(this.FullLogPath, tx.Hash.ToString() + ".llvmhex.txt");
                            if (engine.FullLog != null)
                            {
                                engine.FullLog.Save(filename);
                            }
                        }
                    }
                    break;
                }
            }
            accounts.DeleteWhere((k, v) => !v.IsFrozen && v.Votes.Length == 0 && v.Balances.All(p => p.Value <= Fixed8.Zero));
            accounts.Commit();
            unspentcoins.DeleteWhere((k, v) => v.Items.All(p => p.HasFlag(CoinState.Spent)));
            unspentcoins.Commit();
            spentcoins.DeleteWhere((k, v) => v.Items.Count == 0);
            spentcoins.Commit();
            validators.Commit();
            assets.Commit();
            contracts.Commit();
            storages.Commit();
            validators_count.Commit(batch);
            batch.Put(SliceBuilder.Begin(DataEntryPrefix.SYS_CurrentBlock), SliceBuilder.Begin().Add(block.Hash).Add(block.Index));
            db.Write(WriteOptions.Default, batch);
            current_block_height = block.Index;
        }
Ejemplo n.º 3
0
        private void Persist(Block block)
        {
            using (Snapshot snapshot = GetSnapshot())
            {
                List <ApplicationExecuted> all_application_executed = new List <ApplicationExecuted>();
                snapshot.PersistingBlock = block;
                snapshot.Blocks.Add(block.Hash, new BlockState
                {
                    SystemFeeAmount = snapshot.GetSysFeeAmount(block.PrevHash) + (long)block.Transactions.Sum(p => p.SystemFee),
                    TrimmedBlock    = block.Trim()
                });
                foreach (Transaction tx in block.Transactions)
                {
                    snapshot.Transactions.Add(tx.Hash, new TransactionState
                    {
                        BlockIndex  = block.Index,
                        Transaction = tx
                    });
                    snapshot.UnspentCoins.Add(tx.Hash, new UnspentCoinState
                    {
                        Items = Enumerable.Repeat(CoinState.Confirmed, tx.Outputs.Length).ToArray()
                    });
                    foreach (TransactionOutput output in tx.Outputs)
                    {
                        AccountState account = snapshot.Accounts.GetAndChange(output.ScriptHash, () => new AccountState(output.ScriptHash));
                        if (account.Balances.ContainsKey(output.AssetId))
                        {
                            account.Balances[output.AssetId] += output.Value;
                        }
                        else
                        {
                            account.Balances[output.AssetId] = output.Value;
                        }
                        if (output.AssetId.Equals(GoverningToken.Hash) && account.Votes.Length > 0)
                        {
                            foreach (ECPoint pubkey in account.Votes)
                            {
                                snapshot.Validators.GetAndChange(pubkey, () => new ValidatorState(pubkey)).Votes += output.Value;
                            }
                            snapshot.ValidatorsCount.GetAndChange().Votes[account.Votes.Length - 1] += output.Value;
                        }
                    }
                    foreach (var group in tx.Inputs.GroupBy(p => p.PrevHash))
                    {
                        TransactionState tx_prev = snapshot.Transactions[group.Key];
                        foreach (CoinReference input in group)
                        {
                            snapshot.UnspentCoins.GetAndChange(input.PrevHash).Items[input.PrevIndex] |= CoinState.Spent;
                            TransactionOutput out_prev = tx_prev.Transaction.Outputs[input.PrevIndex];
                            AccountState      account  = snapshot.Accounts.GetAndChange(out_prev.ScriptHash);
                            if (out_prev.AssetId.Equals(GoverningToken.Hash))
                            {
                                snapshot.SpentCoins.GetAndChange(input.PrevHash, () => new SpentCoinState
                                {
                                    TransactionHash   = input.PrevHash,
                                    TransactionHeight = tx_prev.BlockIndex,
                                    Items             = new Dictionary <ushort, uint>()
                                }).Items.Add(input.PrevIndex, block.Index);
                                if (account.Votes.Length > 0)
                                {
                                    foreach (ECPoint pubkey in account.Votes)
                                    {
                                        ValidatorState validator = snapshot.Validators.GetAndChange(pubkey);
                                        validator.Votes -= out_prev.Value;
                                        if (!validator.Registered && validator.Votes.Equals(Fixed8.Zero))
                                        {
                                            snapshot.Validators.Delete(pubkey);
                                        }
                                    }
                                    snapshot.ValidatorsCount.GetAndChange().Votes[account.Votes.Length - 1] -= out_prev.Value;
                                }
                            }
                            account.Balances[out_prev.AssetId] -= out_prev.Value;
                        }
                    }
                    List <ApplicationExecutionResult> execution_results = new List <ApplicationExecutionResult>();
                    switch (tx)
                    {
#pragma warning disable CS0612
                    case RegisterTransaction tx_register:
                        snapshot.Assets.Add(tx.Hash, new AssetState
                        {
                            AssetId    = tx_register.Hash,
                            AssetType  = tx_register.AssetType,
                            Name       = tx_register.Name,
                            Amount     = tx_register.Amount,
                            Available  = Fixed8.Zero,
                            Precision  = tx_register.Precision,
                            Fee        = Fixed8.Zero,
                            FeeAddress = new UInt160(),
                            Owner      = tx_register.Owner,
                            Admin      = tx_register.Admin,
                            Issuer     = tx_register.Admin,
                            Expiration = block.Index + 2 * 2000000,
                            IsFrozen   = false
                        });
                        break;

#pragma warning restore CS0612
                    case IssueTransaction _:
                        foreach (TransactionResult result in tx.GetTransactionResults().Where(p => p.Amount < Fixed8.Zero))
                        {
                            snapshot.Assets.GetAndChange(result.AssetId).Available -= result.Amount;
                        }
                        break;

                    case ClaimTransaction _:
                        foreach (CoinReference input in ((ClaimTransaction)tx).Claims)
                        {
                            if (snapshot.SpentCoins.TryGet(input.PrevHash)?.Items.Remove(input.PrevIndex) == true)
                            {
                                snapshot.SpentCoins.GetAndChange(input.PrevHash);
                            }
                        }
                        break;

#pragma warning disable CS0612
                    case EnrollmentTransaction tx_enrollment:
                        snapshot.Validators.GetAndChange(tx_enrollment.PublicKey, () => new ValidatorState(tx_enrollment.PublicKey)).Registered = true;
                        break;

#pragma warning restore CS0612
                    case StateTransaction tx_state:
                        foreach (StateDescriptor descriptor in tx_state.Descriptors)
                        {
                            switch (descriptor.Type)
                            {
                            case StateType.Account:
                                ProcessAccountStateDescriptor(descriptor, snapshot);
                                break;

                            case StateType.Validator:
                                ProcessValidatorStateDescriptor(descriptor, snapshot);
                                break;
                            }
                        }
                        break;

#pragma warning disable CS0612
                    case PublishTransaction tx_publish:
                        snapshot.Contracts.GetOrAdd(tx_publish.ScriptHash, () => new ContractState
                        {
                            Script             = tx_publish.Script,
                            ParameterList      = tx_publish.ParameterList,
                            ReturnType         = tx_publish.ReturnType,
                            ContractProperties = (ContractPropertyState)Convert.ToByte(tx_publish.NeedStorage),
                            Name        = tx_publish.Name,
                            CodeVersion = tx_publish.CodeVersion,
                            Author      = tx_publish.Author,
                            Email       = tx_publish.Email,
                            Description = tx_publish.Description
                        });
                        break;

#pragma warning restore CS0612
                    case InvocationTransaction tx_invocation:
                        using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, tx_invocation, snapshot.Clone(), tx_invocation.Gas))
                        {
                            engine.LoadScript(tx_invocation.Script);
                            engine.Execute();
                            if (!engine.State.HasFlag(VMState.FAULT))
                            {
                                engine.Service.Commit();
                            }
                            execution_results.Add(new ApplicationExecutionResult
                            {
                                Trigger       = TriggerType.Application,
                                ScriptHash    = tx_invocation.Script.ToScriptHash(),
                                VMState       = engine.State,
                                GasConsumed   = engine.GasConsumed,
                                Stack         = engine.ResultStack.ToArray(),
                                Notifications = engine.Service.Notifications.ToArray()
                            });
                        }
                        break;
                    }
                    if (execution_results.Count > 0)
                    {
                        ApplicationExecuted application_executed = new ApplicationExecuted
                        {
                            Transaction      = tx,
                            ExecutionResults = execution_results.ToArray()
                        };
                        Context.System.EventStream.Publish(application_executed);
                        all_application_executed.Add(application_executed);
                    }
                }
                snapshot.BlockHashIndex.GetAndChange().Hash  = block.Hash;
                snapshot.BlockHashIndex.GetAndChange().Index = block.Index;
                if (block.Index == header_index.Count)
                {
                    header_index.Add(block.Hash);
                    snapshot.HeaderHashIndex.GetAndChange().Hash  = block.Hash;
                    snapshot.HeaderHashIndex.GetAndChange().Index = block.Index;
                }
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    plugin.OnPersist(snapshot, all_application_executed);
                }
                snapshot.Commit();
                List <Exception> commitExceptions = null;
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    try
                    {
                        plugin.OnCommit(snapshot);
                    }
                    catch (Exception ex)
                    {
                        if (plugin.ShouldThrowExceptionFromCommit(ex))
                        {
                            if (commitExceptions == null)
                            {
                                commitExceptions = new List <Exception>();
                            }

                            commitExceptions.Add(ex);
                        }
                    }
                }
                if (commitExceptions != null)
                {
                    throw new AggregateException(commitExceptions);
                }
            }
            UpdateCurrentSnapshot();
            OnPersistCompleted(block);
        }
Ejemplo n.º 4
0
        private void Persist(Block block)
        {
            using (Snapshot snapshot = GetSnapshot())
            {
                List <ApplicationExecuted> all_application_executed = new List <ApplicationExecuted>();
                snapshot.PersistingBlock = block;
                if (block.Index > 0)
                {
                    NativeContract[] contracts = { NativeContract.GAS, NativeContract.NEO };
                    using (ApplicationEngine engine = new ApplicationEngine(TriggerType.System, null, snapshot, 0, true))
                    {
                        using (ScriptBuilder sb = new ScriptBuilder())
                        {
                            foreach (NativeContract contract in contracts)
                            {
                                sb.EmitAppCall(contract.Hash, "onPersist");
                            }
                            engine.LoadScript(sb.ToArray());
                        }
                        if (engine.Execute() != VMState.HALT)
                        {
                            throw new InvalidOperationException();
                        }
                        ApplicationExecuted application_executed = new ApplicationExecuted(engine);
                        Context.System.EventStream.Publish(application_executed);
                        all_application_executed.Add(application_executed);
                    }
                }
                snapshot.Blocks.Add(block.Hash, block.Trim());
                foreach (Transaction tx in block.Transactions)
                {
                    var state = new TransactionState
                    {
                        BlockIndex  = block.Index,
                        Transaction = tx
                    };

                    snapshot.Transactions.Add(tx.Hash, state);

                    using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, tx, snapshot.Clone(), tx.SystemFee))
                    {
                        engine.LoadScript(tx.Script);
                        state.VMState = engine.Execute();
                        if (state.VMState == VMState.HALT)
                        {
                            engine.Snapshot.Commit();
                        }
                        ApplicationExecuted application_executed = new ApplicationExecuted(engine);
                        Context.System.EventStream.Publish(application_executed);
                        all_application_executed.Add(application_executed);
                    }
                }
                snapshot.BlockHashIndex.GetAndChange().Hash  = block.Hash;
                snapshot.BlockHashIndex.GetAndChange().Index = block.Index;
                if (block.Index == header_index.Count)
                {
                    header_index.Add(block.Hash);
                    snapshot.HeaderHashIndex.GetAndChange().Hash  = block.Hash;
                    snapshot.HeaderHashIndex.GetAndChange().Index = block.Index;
                }
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    plugin.OnPersist(snapshot, all_application_executed);
                }
                snapshot.Commit();
                List <Exception> commitExceptions = null;
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    try
                    {
                        plugin.OnCommit(snapshot);
                    }
                    catch (Exception ex)
                    {
                        if (plugin.ShouldThrowExceptionFromCommit(ex))
                        {
                            if (commitExceptions == null)
                            {
                                commitExceptions = new List <Exception>();
                            }

                            commitExceptions.Add(ex);
                        }
                    }
                }
                if (commitExceptions != null)
                {
                    throw new AggregateException(commitExceptions);
                }
            }
            UpdateCurrentSnapshot();
            OnPersistCompleted(block);
        }
Ejemplo n.º 5
0
        private void Persist(Block block)
        {
            using (Snapshot snapshot = GetSnapshot())
            {
                List <ApplicationExecuted> all_application_executed = new List <ApplicationExecuted>();
                snapshot.PersistingBlock = block;
                if (block.Index > 0)
                {
                    snapshot.NextValidators.GetAndChange().Validators = snapshot.GetValidators();
                }
                snapshot.Blocks.Add(block.Hash, new BlockState
                {
                    SystemFeeAmount = snapshot.GetSysFeeAmount(block.PrevHash) + (long)block.Transactions.Sum(p => p.SystemFee),
                    TrimmedBlock    = block.Trim()
                });
                foreach (Transaction tx in block.Transactions)
                {
                    snapshot.Transactions.Add(tx.Hash, new TransactionState
                    {
                        BlockIndex  = block.Index,
                        Transaction = tx
                    });
                    snapshot.UnspentCoins.Add(tx.Hash, new UnspentCoinState
                    {
                        Items = Enumerable.Repeat(CoinState.Confirmed, tx.Outputs.Length).ToArray()
                    });
                    foreach (CoinReference input in tx.Inputs)
                    {
                        snapshot.UnspentCoins.GetAndChange(input.PrevHash).Items[input.PrevIndex] |= CoinState.Spent;
                    }
                    List <ApplicationExecutionResult> execution_results = new List <ApplicationExecutionResult>();
                    switch (tx)
                    {
#pragma warning disable CS0612
                    case RegisterTransaction tx_register:
                        snapshot.Assets.Add(tx.Hash, new AssetState
                        {
                            AssetId    = tx_register.Hash,
                            AssetType  = tx_register.AssetType,
                            Name       = tx_register.Name,
                            Amount     = tx_register.Amount,
                            Available  = Fixed8.Zero,
                            Precision  = tx_register.Precision,
                            Fee        = Fixed8.Zero,
                            FeeAddress = new UInt160(),
                            Owner      = tx_register.Owner,
                            Admin      = tx_register.Admin,
                            Issuer     = tx_register.Admin,
                            Expiration = block.Index + 2 * 2000000,
                            IsFrozen   = false
                        });
                        break;

#pragma warning restore CS0612
                    case InvocationTransaction tx_invocation:
                        using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, tx_invocation, snapshot.Clone(), tx_invocation.Gas))
                        {
                            engine.LoadScript(tx_invocation.Script);
                            engine.Execute();
                            if (!engine.State.HasFlag(VMState.FAULT))
                            {
                                engine.Service.Commit();
                            }
                            execution_results.Add(new ApplicationExecutionResult
                            {
                                Trigger       = TriggerType.Application,
                                ScriptHash    = tx_invocation.Script.ToScriptHash(),
                                VMState       = engine.State,
                                GasConsumed   = engine.GasConsumed,
                                Stack         = engine.ResultStack.ToArray(),
                                Notifications = engine.Service.Notifications.ToArray()
                            });
                        }
                        break;
                    }
                    if (execution_results.Count > 0)
                    {
                        ApplicationExecuted application_executed = new ApplicationExecuted
                        {
                            Transaction      = tx,
                            ExecutionResults = execution_results.ToArray()
                        };
                        Context.System.EventStream.Publish(application_executed);
                        all_application_executed.Add(application_executed);
                    }
                }
                snapshot.BlockHashIndex.GetAndChange().Hash  = block.Hash;
                snapshot.BlockHashIndex.GetAndChange().Index = block.Index;
                if (block.Index == header_index.Count)
                {
                    header_index.Add(block.Hash);
                    snapshot.HeaderHashIndex.GetAndChange().Hash  = block.Hash;
                    snapshot.HeaderHashIndex.GetAndChange().Index = block.Index;
                }
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    plugin.OnPersist(snapshot, all_application_executed);
                }
                snapshot.Commit();
                List <Exception> commitExceptions = null;
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    try
                    {
                        plugin.OnCommit(snapshot);
                    }
                    catch (Exception ex)
                    {
                        if (plugin.ShouldThrowExceptionFromCommit(ex))
                        {
                            if (commitExceptions == null)
                            {
                                commitExceptions = new List <Exception>();
                            }

                            commitExceptions.Add(ex);
                        }
                    }
                }
                if (commitExceptions != null)
                {
                    throw new AggregateException(commitExceptions);
                }
            }
            UpdateCurrentSnapshot();
            OnPersistCompleted(block);
        }
Ejemplo n.º 6
0
        private void Persist(Block block)
        {
            using (SnapshotCache snapshot = system.GetSnapshot())
            {
                List <ApplicationExecuted> all_application_executed = new List <ApplicationExecuted>();
                using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.OnPersist, null, snapshot, block))
                {
                    engine.LoadScript(onPersistScript);
                    if (engine.Execute() != VMState.HALT)
                    {
                        throw new InvalidOperationException();
                    }
                    ApplicationExecuted application_executed = new ApplicationExecuted(engine);
                    Context.System.EventStream.Publish(application_executed);
                    all_application_executed.Add(application_executed);
                }
                DataCache clonedSnapshot = snapshot.CreateSnapshot();
                // Warning: Do not write into variable snapshot directly. Write into variable clonedSnapshot and commit instead.
                foreach (Transaction tx in block.Transactions)
                {
                    using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, tx, clonedSnapshot, block, tx.SystemFee))
                    {
                        engine.LoadScript(tx.Script);
                        if (engine.Execute() == VMState.HALT)
                        {
                            clonedSnapshot.Commit();
                        }
                        else
                        {
                            clonedSnapshot = snapshot.CreateSnapshot();
                        }
                        ApplicationExecuted application_executed = new ApplicationExecuted(engine);
                        Context.System.EventStream.Publish(application_executed);
                        all_application_executed.Add(application_executed);
                    }
                }
                using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.PostPersist, null, snapshot, block))
                {
                    engine.LoadScript(postPersistScript);
                    if (engine.Execute() != VMState.HALT)
                    {
                        throw new InvalidOperationException();
                    }
                    ApplicationExecuted application_executed = new ApplicationExecuted(engine);
                    Context.System.EventStream.Publish(application_executed);
                    all_application_executed.Add(application_executed);
                }
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    plugin.OnPersist(block, snapshot, all_application_executed);
                }
                snapshot.Commit();
                List <Exception> commitExceptions = null;
                foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins)
                {
                    try
                    {
                        plugin.OnCommit(block, snapshot);
                    }
                    catch (Exception ex)
                    {
                        if (plugin.ShouldThrowExceptionFromCommit(ex))
                        {
                            if (commitExceptions == null)
                            {
                                commitExceptions = new List <Exception>();
                            }

                            commitExceptions.Add(ex);
                        }
                    }
                }
                if (commitExceptions != null)
                {
                    throw new AggregateException(commitExceptions);
                }
                system.MemPool.UpdatePoolForBlockPersisted(block, snapshot);
            }
            extensibleWitnessWhiteList = null;
            block_cache.Remove(block.PrevHash);
            Context.System.EventStream.Publish(new PersistCompleted {
                Block = block
            });
            if (system.HeaderCache.TryRemoveFirst(out Header header))
            {
                Debug.Assert(header.Index == block.Index);
            }
        }