Exemple #1
0
        private static void SendNotification(PublishTransaction subject, SaveEventArgs e, EventPhases phases)
        {
            // only send a message when the publishing is finished. The publish transaction gets saved at least when created and on a status update
            if (!subject.IsCompleted)
            {
                return;
            }

            // create an object that contains some data that we want to send to the client as the details of the message
            JObject details = JObject.FromObject(new
            {
                creatorId = subject.Creator.Id.ToString(),
                state     = subject.State.ToString(),
                title     = subject.Title
            });

            NotificationMessage message = new NotificationMessage
            {
                // we need an identifier that we can use in the UI extension to distinguish our messages from others
                Action     = "example:publishtransactionfinished",
                SubjectIds = new[] { subject.Id.ToString() },
                Details    = details.ToString()
            };

            subject.Session.NotificationsManager.BroadcastNotification(message);
        }
        /// <summary>
        /// Try to identify if the given publish result contains the TcmUri to check
        /// </summary>
        /// <param name="transaction">The transaction to find.</param>
        /// <param name="tcmUri">String Tcm Uri to check</param>
        /// <returns>true if found; false, otherwise</returns>
        private static bool IsPublishTransactionForTcmUri(PublishTransaction transaction, String tcmUri)
        {
            IList <IdentifiableObject> items = transaction.Items;

            foreach (IdentifiableObject item in items)
            {
                if (item.Id.ToString().Equals(tcmUri))
                {
                    return(true);
                }
            }

            foreach (PublishContext context in transaction.PublishContexts)
            {
                foreach (ProcessedItem processedItem in transaction.GetListProcessedItems(context))
                {
                    IdentifiableObject item = processedItem.ResolvedItem.Item;
                    if (item.Id.ToString().Equals(tcmUri))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        public async Task Persist_AddContract()
        {
            var input = new PublishTransaction
            {
                Script        = RandomByteArray(10),
                Description   = RandomString(10),
                ReturnType    = (ContractParameterType)RandomInt(10),
                ParameterList = new[] { (ContractParameterType)RandomInt(10), (ContractParameterType)RandomInt(10) },
                Name          = RandomString(10),
                Version       = (byte)RandomInt(10),
                Author        = RandomString(10),
                Email         = RandomString(10)
            };
            var repositoryMock = AutoMockContainer.GetMock <IRepository>();
            var testee         = AutoMockContainer.Create <PublishTransactionPersister>();

            await testee.Persist(input);

            repositoryMock.Verify(m => m.AddContract(It.Is <Contract>(c =>
                                                                      c.Code != null &&
                                                                      c.Code.ScriptHash.Equals(input.Script.ToScriptHash()) &&
                                                                      c.Code.Script == input.Script &&
                                                                      c.Code.ReturnType == input.ReturnType &&
                                                                      c.Code.Parameters == input.ParameterList &&
                                                                      c.Name == input.Name &&
                                                                      c.Version == input.CodeVersion &&
                                                                      c.Author == input.Author &&
                                                                      c.Email == input.Email &&
                                                                      c.Description == input.Description)));
        }
        /// <summary>
        /// Get 'current' PublishTransaction. It tries to identify a PublishTransaction from the publish queue that is on the
        /// given TcmUri, Publication, User, etc.
        /// </summary>
        /// <param name="engine">Engine object</param>
        /// <param name="tcmUri">String representing the tcmuri of the item to check</param>
        /// <returns>PublishTransaction if found; or null, otherwise</returns>
        private static PublishTransaction FindPublishTransaction(Engine engine, String tcmUri)
        {
            Log.Debug(String.Format("Find PublishTransaction for item '{0}'", tcmUri));

            PublishTransaction        result  = null;
            Session                   session = engine.GetSession();
            PublishTransactionsFilter filter  = new PublishTransactionsFilter(session);

            filter.PublishTransactionState = PublishTransactionState.Resolving;
            RepositoryLocalObject item = engine.GetObject(tcmUri) as RepositoryLocalObject;

            if (item != null)
            {
                filter.ForRepository = item.ContextRepository;
            }

            PublicationTarget publicationTarget = engine.PublishingContext.PublicationTarget;

            if (publicationTarget != null)
            {
                filter.PublicationTarget = publicationTarget;
            }

            XmlElement element = PublishEngine.GetListPublishTransactions(filter);


            XmlNamespaceManager namespaceManager = new XmlNamespaceManager(new NameTable());

            namespaceManager.AddNamespace("tcm", "http://www.tridion.com/ContentManager/5.0");

            String      xPath    = String.Format("tcm:ListPublishTransactions/tcm:Item[@ItemID='{0}']", tcmUri);
            XmlNodeList nodeList = element.SelectNodes(xPath, namespaceManager);

            String transactionId;

            if (nodeList != null && nodeList.Count == 1)
            {
                transactionId = nodeList[0].Attributes["ID"].Value;
                TcmUri transactionUri = new TcmUri(transactionId);
                result = new PublishTransaction(transactionUri, session);
            }
            else
            {
                foreach (XmlNode node in element.ChildNodes)
                {
                    transactionId = node.Attributes["ID"].Value;
                    TcmUri transactionUri = new TcmUri(transactionId);
                    result = new PublishTransaction(transactionUri, session);
                    if (IsPublishTransactionForTcmUri(result, tcmUri))
                    {
                        break;
                    }
                    result = null;
                }
            }

            Log.Debug("Returning PublishTransaction " + result);
            return(result);
        }
        /// <summary>
        /// Execute the transformation for the specified template
        /// </summary>
        /// <param name="Engine"><see cref="T:Tridion.ContentManager.Templating.Engine"/>.</param>
        /// <param name="Package"><see cref="T:Tridion.ContentManager.Templating.Package"/></param>
        public void Transform(Engine Engine, Package Package)
        {
            try
            {
                mTicksStart = Environment.TickCount;

                mEngine  = Engine;
                mPackage = Package;

                // Actual template transformation
                PreTransform();
                Transform();
                PostTransform();
            }
            catch (Exception ex)
            {
                String exceptionStack = LoggerExtensions.TraceException(ex);

                Logger.Error("TemplateBase.Transform Exception\n" + exceptionStack);

                StringBuilder sb = new StringBuilder();
                sb.AppendLine(ex.Message);
                sb.AppendFormat("Publisher: {0}\n", Environment.MachineName);
                sb.Append(exceptionStack);

                // Re-throw to ensure Tridion knows what happened
                throw new Exception(sb.ToString(), ex);
            }
            // Ensure we always clean up, no matter what happens during the template transformation
            finally
            {
                Logger.Info("{0}: Render time {1:0.00000} seconds @ {2:dd/MM/yyyy hh:mm:ss tt} ", this.GetType().FullName, ProcessedTime / 1000.0, DateTime.Now);

                // Do not cache objects across template transformations
                ItemFieldsFactory.ClearCache();

                // Clear published binaries list if it was used
                if (mPublishedBinaries.IsValueCreated)
                {
                    mPublishedBinaries.Value.Clear();
                }

                mPackage = null;
                mEngine  = null;
                mLogger  = null;

                mComponent         = null;
                mComponentTemplate = null;
                mPage               = null;
                mPageTemplate       = null;
                mRootStructureGroup = null;
                mPublication        = null;
                mPublishTransaction = null;
                mPublishingUser     = null;
                mPublicationTarget  = null;
            }
        }
Exemple #6
0
        public async Task Persist_PublishTx_CallsPublishTxPersister()
        {
            var input = new PublishTransaction();
            var publishTxPersisterMock = AutoMockContainer.GetMock <ITransactionPersister <PublishTransaction> >();
            var testee = AutoMockContainer.Create <TransactionPersister>();

            await testee.Persist(input);

            publishTxPersisterMock.Verify(m => m.Persist(input));
        }
Exemple #7
0
        public async Task Process_PublishTx_CallsPublishTxProcessor()
        {
            var input = new PublishTransaction();
            var publishTxProcessorMock = AutoMockContainer.GetMock <IProcessor <PublishTransaction> >();
            var testee = AutoMockContainer.Create <TransactionProcessor>();

            await testee.Process(input);

            publishTxProcessorMock.Verify(m => m.Process(input));
        }
Exemple #8
0
        public void SendPublishInfo(PublishTransaction publishTransaction, SaveEventArgs args, EventPhases phase)
        {
            //Get Tcm Uri of publisher user and published Url of page and send info to WebService
            if (publishTransaction.State == PublishTransactionState.Success)
            {
                var page = publishTransaction.Items.First() as Page;

                var publishedInfo = new
                {
                    TCMUri = publishTransaction.Creator.Id,
                    URL    = page.GetPublishUrl(publishTransaction.TargetType).ToString()
                };

                string json = JsonConvert.SerializeObject(publishedInfo, Formatting.Indented);
                SendJson(json);
            }
        }
Exemple #9
0
#pragma warning disable CS0612 // Type or member is obsolete
        public void SerializeDeserialize_PublishTransaction()
        {
            var original = new PublishTransaction()
            {
                Version       = 0x01,
                Author        = RandomString(1, 250),
                Email         = RandomString(1, 250),
                Description   = RandomString(1, 250),
                Name          = RandomString(1, 250),
                CodeVersion   = RandomString(1, 250),
                NeedStorage   = _random.Next() % 2 == 0,
                Script        = RandomBytes(_random.Next(1, short.MaxValue)),
                ParameterList = RandomParameterList(_random.Next(1, 10)).ToArray(),
                ReturnType    = RandomParameterList(1).FirstOrDefault(),
            };

            FillRandomTx(original);

            var ret   = _serializer.Serialize(original);
            var copy  = _deserializer.Deserialize <Transaction>(ret);
            var copy2 = _deserializer.Deserialize <PublishTransaction>(ret);

            // Check exclusive data

            foreach (var check in new PublishTransaction[] { (PublishTransaction)copy, copy2 })
            {
                Assert.AreEqual(original.Author, check.Author);
                Assert.AreEqual(original.Email, check.Email);
                Assert.AreEqual(original.Description, check.Description);
                Assert.AreEqual(original.Name, check.Name);
                Assert.AreEqual(original.CodeVersion, check.CodeVersion);
                Assert.AreEqual(original.NeedStorage, check.NeedStorage);
                Assert.AreEqual(original.Author, check.Author);
                Assert.AreEqual(original.ReturnType, check.ReturnType);
                CollectionAssert.AreEqual(original.Script, check.Script);
                CollectionAssert.AreEqual(original.ParameterList, check.ParameterList);
            }

            // Check base data

            EqualTx(original, copy, copy2);
        }
        /// <summary>
        /// Publishes an <see cref="T:Tridion.ContentManager.IdentifiableObject" /> intelligently if and only if, <see cref="T:Tridion.ContentManager.IdentifiableObject" /> is not in
        /// "Waiting For Publish" state or "Scheduled For Publish" state within the scheduleDateFilter <see cref="T:System.DateTime" />
        /// </summary>
        /// <param name="identifiableObject">The <see cref="T:Tridion.ContentManager.IdentifiableObject" />.</param>
        /// <param name="startDateFilter">The start <see cref="T:System.DateTime"/> filter.</param>
        /// <param name="scheduleDateFilter">The schedule <see cref="T:System.DateTime"/> filter.</param>
        /// <param name="publishStartDate">The publish start <see cref="T:System.DateTime"/>.</param>
        public void PublishIntelligently(IdentifiableObject identifiableObject, DateTime startDateFilter, DateTime scheduleDateFilter, DateTime publishStartDate)
        {
            PublishTransactionsFilter filter = new PublishTransactionsFilter(Engine.GetSession())
            {
                StartDate         = startDateFilter,
                PublicationTarget = PublicationTarget,
                ForRepository     = GetObject <Repository>(Publication.Id)
            };

            PublishTransaction publishTransaction = PublishEngine.GetPublishTransactions(filter)
                                                    .FirstOrDefault(t => t.Items.Count > 0 &&
                                                                    t.Items.First().Id == identifiableObject.Id &&
                                                                    (t.State == PublishTransactionState.WaitingForPublish ||
                                                                     (t.State == PublishTransactionState.ScheduledForPublish && scheduleDateFilter >= t.Instruction.StartAt)));

            if (publishTransaction == null)
            {
                PublishItem(identifiableObject, publishStartDate);
            }
        }
        private void PublishTransactionSaveAction(PublishTransaction subject, SaveEventArgs args, EventPhases phases)
        {
            // ignore items in website structure publication (they are always empty because of the child publications only resolver)
            if (subject.PublishContexts[0].Publication.Id.ItemId == _websiteStructurePublicationUri.ItemId)
            {
                return;
            }

            // after the publisher has used the Resolve Engine to figure out what to publish/render or unpublish,
            // it reflects the resolved results in PublishTransaction.PublishContexts[0].ProcessedItems
            // currently there will always be exactly one PublishContext per PublishTransaction
            if (subject.PublishContexts[0].ProcessedItems.Count == 0 && subject.State.Equals(PublishTransactionState.Success))
            {
                // change state to warning and inform that this publish transaction had 0 items
                // could change state by setting property PublishTransaction.State,
                // but the property PublishTransaction.Information is readonly, so let's use IdentifiableObject.Update
                XmlDocument delta = new XmlDocument();
                delta.LoadXml(string.Format(DeltaXml, Constants.TcmR6Namespace, subject.Id, Message, PublishTransactionState.Warning));
                subject.Update(delta.DocumentElement);
            }
        }
 private void PublishTransactionSaveAction(PublishTransaction subject, SaveEventArgs args, EventPhases phases)
 {
     // ignore items in website structure publication (they are always empty because of the child publications only resolver)
     if (subject.PublishContexts[0].Publication.Id.ItemId == _websiteStructurePublicationUri.ItemId)
     {
         return;
     }
     
     // after the publisher has used the Resolve Engine to figure out what to publish/render or unpublish, 
     // it reflects the resolved results in PublishTransaction.PublishContexts[0].ProcessedItems
     // currently there will always be exactly one PublishContext per PublishTransaction
     if (subject.PublishContexts[0].ProcessedItems.Count == 0 && subject.State.Equals(PublishTransactionState.Success))
     {
         // change state to warning and inform that this publish transaction had 0 items 
         // could change state by setting property PublishTransaction.State, 
         // but the property PublishTransaction.Information is readonly, so let's use IdentifiableObject.Update 
         XmlDocument delta = new XmlDocument();
         delta.LoadXml(string.Format(DeltaXml, Constants.TcmR6Namespace, subject.Id, Message, PublishTransactionState.Warning));
         subject.Update(delta.DocumentElement);
     }
 }
Exemple #13
0
        /// <summary>
        /// Audits a publishing transaction
        /// </summary>
        /// <param name="transaction"><see cref="T:Tridion.ContentManager.Publishing.PublishTransaction" /></param>
        /// <param name="args">The <see cref="SaveEventArgs"/> instance containing the event data.</param>
        /// <param name="phase"><see cref="T:Tridion.ContentManager.Extensibility.EventPhases" /></param>
        private void AuditPublish(PublishTransaction transaction, SaveEventArgs args, EventPhases phase)
        {
            if (phase == EventPhases.TransactionCommitted && transaction.State == PublishTransactionState.Success)
            {
                try
                {
                    using (SqlConnection connection = Connection)
                    {
                        // Register the publish transaction
                        using (SqlCommand sqlAuditPublishTransaction = new SqlCommand()
                        {
                            CommandText = "AuditPublishTransaction",
                            CommandType = CommandType.StoredProcedure,
                            Connection = connection
                        })
                        {
                            sqlAuditPublishTransaction.AddParameter("@Transaction", SqlDbType.VarChar, transaction.Id.ToString());
                            sqlAuditPublishTransaction.AddParameter("@Action", SqlDbType.VarChar, (transaction.Instruction is PublishInstruction ? "Publish" : "Unpublish"));
                            sqlAuditPublishTransaction.AddParameter("@TimeStamp", SqlDbType.DateTime, transaction.StateChangeDateTime);
                            sqlAuditPublishTransaction.AddParameter("@Username", SqlDbType.VarChar, transaction.Creator.Title.ToUpper());
                            sqlAuditPublishTransaction.AddParameter("@UserDescription", SqlDbType.NVarChar, transaction.Creator.Description);

                            int transactionId = Convert.ToInt32(sqlAuditPublishTransaction.ExecuteScalar());

                            if (transactionId > 0)
                            {
                                using (SqlCommand sqlAuditPublishedItem = new SqlCommand()
                                {
                                    CommandText = "AuditPublishedItem",
                                    CommandType = CommandType.StoredProcedure,
                                    Connection = connection
                                })
                                {
                                    // Register the publication transaction
                                    sqlAuditPublishedItem.AddParameter("@TransactionID", SqlDbType.Int, transactionId);
                                    sqlAuditPublishedItem.AddParameter("@PublicationTarget", SqlDbType.VarChar);
                                    sqlAuditPublishedItem.AddParameter("@Publication", SqlDbType.VarChar);
                                    sqlAuditPublishedItem.AddParameter("@ItemID", SqlDbType.VarChar);
                                    sqlAuditPublishedItem.AddParameter("@ItemTitle", SqlDbType.NVarChar);
                                    sqlAuditPublishedItem.AddParameter("@ItemTemplate", SqlDbType.VarChar);
                                    sqlAuditPublishedItem.AddParameter("@IsComponentTemplate", SqlDbType.Bit);
                                    sqlAuditPublishedItem.AddParameter("@IsDCP", SqlDbType.Bit);

                                    foreach (PublishContext publishContext in transaction.PublishContexts)
                                    {
                                        foreach (ProcessedItem processedItem in publishContext.ProcessedItems)
                                        {
                                            // Register each published item
                                            ResolvedItem resolvedItem = processedItem.ResolvedItem;

                                            sqlAuditPublishedItem.SetValue("@PublicationTarget", publishContext.PublicationTarget.Id.ToString());
                                            sqlAuditPublishedItem.SetValue("@Publication", publishContext.Publication.Id.ToString());
                                            sqlAuditPublishedItem.SetValue("@ItemID", resolvedItem.Item.VersionedItemId());
                                            sqlAuditPublishedItem.SetValue("@ItemTitle", resolvedItem.Item.Title);
                                            sqlAuditPublishedItem.SetValue("@ItemTemplate", resolvedItem.Template.VersionedItemId());
                                            sqlAuditPublishedItem.SetValue("@IsComponentTemplate", resolvedItem.IsComponentPresentation);
                                            sqlAuditPublishedItem.SetValue("@IsDCP", resolvedItem.IsDynamicComponentPresentation);

                                            sqlAuditPublishedItem.ExecuteNonQuery();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Write(ex, "TcmEvents.Audit", LoggingCategory.General, TraceEventType.Error);
                }
            }
        }
        /// <summary>
        /// Get 'current' PublishTransaction. It tries to identify a PublishTransaction from the publish queue that is on the 
        /// given TcmUri, Publication, User, etc.
        /// </summary>
        /// <param name="engine">Engine object</param>
        /// <param name="tcmUri">String representing the tcmuri of the item to check</param>
        /// <returns>PublishTransaction if found; or null, otherwise</returns>
        private static PublishTransaction FindPublishTransaction(Engine engine, String tcmUri)
        {
            Log.Debug(String.Format("Find PublishTransaction for item '{0}'", tcmUri));

            PublishTransaction result = null;
            Session session = engine.GetSession();
            PublishTransactionsFilter filter = new PublishTransactionsFilter(session);

            filter.PublishTransactionState = PublishTransactionState.Resolving;
            RepositoryLocalObject item = engine.GetObject(tcmUri) as RepositoryLocalObject;
            if (item != null) filter.ForRepository = item.ContextRepository;

            PublicationTarget publicationTarget = engine.PublishingContext.PublicationTarget;
            if (publicationTarget != null)
            {
                filter.PublicationTarget = publicationTarget;
            }

            XmlElement element = PublishEngine.GetListPublishTransactions(filter);

            XmlNamespaceManager namespaceManager = new XmlNamespaceManager(new NameTable());
            namespaceManager.AddNamespace("tcm", "http://www.tridion.com/ContentManager/5.0");

            String xPath = String.Format("tcm:ListPublishTransactions/tcm:Item[@ItemID='{0}']", tcmUri);
            XmlNodeList nodeList = element.SelectNodes(xPath, namespaceManager);

            String transactionId;
            if (nodeList != null && nodeList.Count == 1)
            {
                transactionId = nodeList[0].Attributes["ID"].Value;
                TcmUri transactionUri = new TcmUri(transactionId);
                result = new PublishTransaction(transactionUri, session);
            }
            else
            {
                foreach (XmlNode node in element.ChildNodes)
                {
                    transactionId = node.Attributes["ID"].Value;
                    TcmUri transactionUri = new TcmUri(transactionId);
                    result = new PublishTransaction(transactionUri, session);
                    if (IsPublishTransactionForTcmUri(result, tcmUri))
                    {
                        break;
                    }
                    result = null;
                }
            }

            Log.Debug("Returning PublishTransaction " + result);
            return result;
        }
        /// <summary>
        /// Try to identify if the given publish result contains the TcmUri to check
        /// </summary>
        /// <param name="transaction">The transaction to find.</param>
        /// <param name="tcmUri">String Tcm Uri to check</param>
        /// <returns>true if found; false, otherwise</returns>
        private static bool IsPublishTransactionForTcmUri(PublishTransaction transaction, String tcmUri)
        {
            IList<IdentifiableObject> items = transaction.Items;
            foreach (IdentifiableObject item in items)
            {
                if (item.Id.ToString().Equals(tcmUri))
                {
                    return true;
                }
            }

            foreach (PublishContext context in transaction.PublishContexts)
            {
                foreach (ProcessedItem processedItem in transaction.GetListProcessedItems(context))
                {
                    IdentifiableObject item = processedItem.ResolvedItem.Item;
                    if (item.Id.ToString().Equals(tcmUri))
                    {
                        return true;
                    }
                }
            }

            return false;
        }
        private void Persist(Block block)
        {
            bool change_cm_merkle_tree = false;

            WriteBatch batch = new WriteBatch();
            DbCache <UInt160, AccountState>     accounts     = new DbCache <UInt160, AccountState>(db, DataEntryPrefix.ST_Account);
            DbCache <UInt256, UnspentCoinState> unspentcoins = new DbCache <UInt256, UnspentCoinState>(db, DataEntryPrefix.ST_Coin);
            DbCache <UInt256, SpentCoinState>   spentcoins   = new DbCache <UInt256, SpentCoinState>(db, DataEntryPrefix.ST_SpentCoin);
            DbCache <ECPoint, ValidatorState>   validators   = new DbCache <ECPoint, ValidatorState>(db, DataEntryPrefix.ST_Validator);
            DbCache <UInt256, AssetState>       assets       = new DbCache <UInt256, AssetState>(db, DataEntryPrefix.ST_Asset);
            DbCache <UInt160, ContractState>    contracts    = new DbCache <UInt160, ContractState>(db, DataEntryPrefix.ST_Contract);
            DbCache <StorageKey, StorageItem>   storages     = new DbCache <StorageKey, StorageItem>(db, DataEntryPrefix.ST_Storage);
            List <NotifyEventArgs> notifications             = new List <NotifyEventArgs>();
            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;
                    }
                }
                foreach (var group in tx.Inputs.GroupBy(p => p.PrevHash))
                {
                    int         height;
                    Transaction tx_prev = GetTransaction(ReadOptions.Default, group.Key, out height);
                    foreach (CoinReference input in group)
                    {
                        unspentcoins.GetAndChange(input.PrevHash).Items[input.PrevIndex] |= CoinState.Spent;
                        if (tx_prev.Outputs[input.PrevIndex].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);
                        }
                        accounts.GetAndChange(tx_prev.Outputs[input.PrevIndex].ScriptHash).Balances[tx_prev.Outputs[input.PrevIndex].AssetId] -= tx_prev.Outputs[input.PrevIndex].Value;
                    }
                }
                switch (tx.Type)
                {
                case TransactionType.RingConfidentialTransaction:
                {
                    if (tx is RingConfidentialTransaction ctx)
                    {
                        for (int i = 0; i < ctx.RingCTSig.Count; i++)
                        {
                            // Add the I Commitment to blockchain.
                            for (int j = 0; j < ctx.RingCTSig[i].MG.II.Count; j++)
                            {
                                batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_RingCTCommitment).Add(ctx.RingCTSig[i].MG.II[j]), SliceBuilder.Begin().Add(ctx.RingCTSig[i].AssetID));
                            }
                        }
                    }
                }
                break;

                case TransactionType.AnonymousContractTransaction:
                {
                    if (tx is AnonymousContractTransaction ctx)
                    {
                        for (int jsIndex = 0; jsIndex < ctx.byJoinSplit.Count; jsIndex++)
                        {
                            batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_Nullifier).Add(ctx.Nullifiers(jsIndex)[0]), SliceBuilder.Begin().Add(ctx.Asset_ID(jsIndex)));
                            batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_Nullifier).Add(ctx.Nullifiers(jsIndex)[1]), SliceBuilder.Begin().Add(ctx.Asset_ID(jsIndex)));

                            SnarkDllApi.AppendCommitment(gCmMerkleTree, ctx.Commitments(jsIndex)[0].ToArray());
                            SnarkDllApi.AppendCommitment(gCmMerkleTree, ctx.Commitments(jsIndex)[1].ToArray());
                        }

                        change_cm_merkle_tree = true;
                    }
                }
                break;

                case TransactionType.RegisterTransaction:
                {
#pragma warning disable CS0612
                    RegisterTransaction rtx = (RegisterTransaction)tx;
                    assets.Add(tx.Hash, new AssetState
                        {
                            AssetId    = rtx.Hash,
                            AssetType  = rtx.AssetType,
                            Name       = rtx.Name,
                            Amount     = rtx.Amount,
                            Available  = Fixed8.Zero,
                            Precision  = rtx.Precision,
                            Fee        = rtx.T_Fee,
                            FeeMin     = rtx.T_Fee_Min,
                            FeeMax     = rtx.T_Fee_Max,
                            AFee       = rtx.A_Fee,
                            FeeAddress = new UInt160(),
                            Owner      = rtx.Owner,
                            Admin      = rtx.Admin,
                            Issuer     = rtx.Admin,
                            Expiration = block.Index + 2 * 2000000,
                            IsFrozen   = false
                        });
#pragma warning restore CS0612
                }
                break;

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

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

                case TransactionType.EnrollmentTransaction:
                {
#pragma warning disable CS0612
                    EnrollmentTransaction enroll_tx = (EnrollmentTransaction)tx;
                    validators.GetOrAdd(enroll_tx.PublicKey, () => new ValidatorState
                        {
                            PublicKey = enroll_tx.PublicKey
                        });
#pragma warning restore CS0612
                }
                break;

                case TransactionType.PublishTransaction:
                {
#pragma warning disable CS0612
                    PublishTransaction publish_tx = (PublishTransaction)tx;
                    contracts.GetOrAdd(publish_tx.ScriptHash, () => new ContractState
                        {
                            Script        = publish_tx.Script,
                            ParameterList = publish_tx.ParameterList,
                            ReturnType    = publish_tx.ReturnType,
                            HasStorage    = publish_tx.NeedStorage,
                            Name          = publish_tx.Name,
                            CodeVersion   = publish_tx.CodeVersion,
                            Author        = publish_tx.Author,
                            Email         = publish_tx.Email,
                            Description   = publish_tx.Description
                        });
#pragma warning restore CS0612
                }
                break;

                case TransactionType.InvocationTransaction:
                {
                    InvocationTransaction itx          = (InvocationTransaction)tx;
                    CachedScriptTable     script_table = new CachedScriptTable(contracts);
                    StateMachine          service      = new StateMachine(accounts, validators, assets, contracts, storages);
                    ApplicationEngine     engine       = new ApplicationEngine(TriggerType.Application, itx, script_table, service, itx.Gas);
                    engine.LoadScript(itx.Script, false);
                    if (engine.Execute())
                    {
                        service.Commit();
                        notifications.AddRange(service.Notifications);
                    }
                }
                break;
                }
            }

            if (change_cm_merkle_tree == true)
            {
                int[] outLen = new int[1];
                outLen[0] = 0;
                IntPtr ptrTree = SnarkDllApi.GetCMTreeInBinary(gCmMerkleTree, outLen);

                byte[] byTree = new byte[outLen[0]];
                System.Runtime.InteropServices.Marshal.Copy(ptrTree, byTree, 0, outLen[0]);

                IntPtr ptrRt1 = SnarkDllApi.GetCMRoot(gCmMerkleTree);

                byte[] by_rt = new byte[32];
                System.Runtime.InteropServices.Marshal.Copy(ptrRt1, by_rt, 0, 32);

                UInt256 current_rt = new UInt256(by_rt);

                db.Put(WriteOptions.Default, SliceBuilder.Begin(DataEntryPrefix.AM_CmMerkleTree), byTree);

                mCmMerkleRoots.Add(current_rt);

                while ((int)mCmMerkleRoots.Count - 5 >= stored_cm_root_count)
                {
                    using (MemoryStream ms = new MemoryStream())
                        using (BinaryWriter w = new BinaryWriter(ms))
                        {
                            w.Write(mCmMerkleRoots.Skip((int)stored_cm_root_count).Take(5).ToArray());
                            w.Flush();
                            batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_MerkleRoot).Add(stored_cm_root_count), ms.ToArray());
                        }
                    stored_cm_root_count += 5;
                }

                if (mCmMerkleRoots.Count > stored_cm_root_count)
                {
                    using (MemoryStream ms = new MemoryStream())
                        using (BinaryWriter w = new BinaryWriter(ms))
                        {
                            w.Write(mCmMerkleRoots.Skip((int)stored_cm_root_count).ToArray());
                            w.Flush();
                            batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_MerkleRoot).Add(stored_cm_root_count), ms.ToArray());
                        }
                }
            }

            if (notifications.Count > 0)
            {
                OnNotify(block, notifications.ToArray());
            }
            accounts.DeleteWhere((k, v) => !v.IsFrozen && v.Votes.Length == 0 && v.Balances.All(p => p.Value <= Fixed8.Zero));
            accounts.Commit(batch);
            unspentcoins.DeleteWhere((k, v) => v.Items.All(p => p.HasFlag(CoinState.Spent)));
            unspentcoins.Commit(batch);
            spentcoins.DeleteWhere((k, v) => v.Items.Count == 0);
            spentcoins.Commit(batch);
            validators.Commit(batch);
            assets.Commit(batch);
            contracts.Commit(batch);
            storages.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;
        }
Exemple #17
0
        /// <summary>
        /// Audits a publishing transaction
        /// </summary>
        /// <param name="transaction"><see cref="T:Tridion.ContentManager.Publishing.PublishTransaction" /></param>
        /// <param name="args">The <see cref="SaveEventArgs"/> instance containing the event data.</param>
        /// <param name="phase"><see cref="T:Tridion.ContentManager.Extensibility.EventPhases" /></param>
        private void AuditPublish(PublishTransaction transaction, SaveEventArgs args, EventPhases phase)
        {
            if (phase == EventPhases.TransactionCommitted && transaction.State == PublishTransactionState.Success)
            {
                try
                {
                    using (SqlConnection connection = Connection)
                    {
                        // Register the publish transaction
                        using (SqlCommand sqlAuditPublishTransaction = new SqlCommand()
                        {
                            CommandText = "AuditPublishTransaction",
                            CommandType = CommandType.StoredProcedure,
                            Connection = connection
                        })
                        {
                            sqlAuditPublishTransaction.AddParameter("@Transaction", SqlDbType.VarChar, transaction.Id.ToString());
                            sqlAuditPublishTransaction.AddParameter("@Action", SqlDbType.VarChar, (transaction.Instruction is PublishInstruction ? "Publish" : "Unpublish"));
                            sqlAuditPublishTransaction.AddParameter("@TimeStamp", SqlDbType.DateTime, transaction.StateChangeDateTime);
                            sqlAuditPublishTransaction.AddParameter("@Username", SqlDbType.VarChar, transaction.Creator.Title.ToUpper());
                            sqlAuditPublishTransaction.AddParameter("@UserDescription", SqlDbType.NVarChar, transaction.Creator.Description);

                            int transactionId = Convert.ToInt32(sqlAuditPublishTransaction.ExecuteScalar());

                            if (transactionId > 0)
                            {
                                using (SqlCommand sqlAuditPublishedItem = new SqlCommand()
                                {
                                    CommandText = "AuditPublishedItem",
                                    CommandType = CommandType.StoredProcedure,
                                    Connection = connection
                                })
                                {
                                    // Register the publication transaction
                                    sqlAuditPublishedItem.AddParameter("@TransactionID", SqlDbType.Int, transactionId);
                                    sqlAuditPublishedItem.AddParameter("@PublicationTarget", SqlDbType.VarChar);
                                    sqlAuditPublishedItem.AddParameter("@Publication", SqlDbType.VarChar);
                                    sqlAuditPublishedItem.AddParameter("@ItemID", SqlDbType.VarChar);
                                    sqlAuditPublishedItem.AddParameter("@ItemTitle", SqlDbType.NVarChar);
                                    sqlAuditPublishedItem.AddParameter("@ItemTemplate", SqlDbType.VarChar);
                                    sqlAuditPublishedItem.AddParameter("@IsComponentTemplate", SqlDbType.Bit);
                                    sqlAuditPublishedItem.AddParameter("@IsDCP", SqlDbType.Bit);

                                    foreach (PublishContext publishContext in transaction.PublishContexts)
                                    {
                                        foreach (ProcessedItem processedItem in publishContext.ProcessedItems)
                                        {
                                            // Register each published item
                                            ResolvedItem resolvedItem = processedItem.ResolvedItem;

                                            sqlAuditPublishedItem.SetValue("@PublicationTarget", publishContext.PublicationTarget.Id.ToString());
                                            sqlAuditPublishedItem.SetValue("@Publication", publishContext.Publication.Id.ToString());
                                            sqlAuditPublishedItem.SetValue("@ItemID", resolvedItem.Item.VersionedItemId());
                                            sqlAuditPublishedItem.SetValue("@ItemTitle", resolvedItem.Item.Title);
                                            sqlAuditPublishedItem.SetValue("@ItemTemplate", resolvedItem.Template.VersionedItemId());
                                            sqlAuditPublishedItem.SetValue("@IsComponentTemplate", resolvedItem.IsComponentPresentation);
                                            sqlAuditPublishedItem.SetValue("@IsDCP", resolvedItem.IsDynamicComponentPresentation);

                                            sqlAuditPublishedItem.ExecuteNonQuery();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Write(ex, "TcmEvents.Audit", LoggingCategory.General, TraceEventType.Error);
                }
            }
        }
        private void Persist(Block block)
        {
            WriteBatch batch = new WriteBatch();
            DbCache <UInt160, AccountState>     accounts     = new DbCache <UInt160, AccountState>(db, DataEntryPrefix.ST_Account);
            DbCache <UInt256, UnspentCoinState> unspentcoins = new DbCache <UInt256, UnspentCoinState>(db, DataEntryPrefix.ST_Coin);
            DbCache <UInt256, SpentCoinState>   spentcoins   = new DbCache <UInt256, SpentCoinState>(db, DataEntryPrefix.ST_SpentCoin);
            DbCache <ECPoint, ValidatorState>   validators   = new DbCache <ECPoint, ValidatorState>(db, DataEntryPrefix.ST_Validator);
            DbCache <UInt256, AssetState>       assets       = new DbCache <UInt256, AssetState>(db, DataEntryPrefix.ST_Asset);
            DbCache <UInt160, ContractState>    contracts    = new DbCache <UInt160, ContractState>(db, DataEntryPrefix.ST_Contract);
            DbCache <StorageKey, StorageItem>   storages     = new DbCache <StorageKey, StorageItem>(db, DataEntryPrefix.ST_Storage);
            List <NotifyEventArgs> notifications             = new List <NotifyEventArgs>();
            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;
                    }
                }
                foreach (var group in tx.Inputs.GroupBy(p => p.PrevHash))
                {
                    int         height;
                    Transaction tx_prev = GetTransaction(ReadOptions.Default, group.Key, out height);
                    foreach (CoinReference input in group)
                    {
                        unspentcoins.GetAndChange(input.PrevHash).Items[input.PrevIndex] |= CoinState.Spent;
                        if (tx_prev.Outputs[input.PrevIndex].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);
                        }
                        accounts.GetAndChange(tx_prev.Outputs[input.PrevIndex].ScriptHash).Balances[tx_prev.Outputs[input.PrevIndex].AssetId] -= tx_prev.Outputs[input.PrevIndex].Value;
                    }
                }
                switch (tx.Type)
                {
                case TransactionType.RegisterTransaction:
                {
#pragma warning disable CS0612
                    RegisterTransaction rtx = (RegisterTransaction)tx;
                    assets.Add(tx.Hash, new AssetState
                        {
                            AssetId    = rtx.Hash,
                            AssetType  = rtx.AssetType,
                            Name       = rtx.Name,
                            Amount     = rtx.Amount,
                            Available  = Fixed8.Zero,
                            Precision  = rtx.Precision,
                            Fee        = Fixed8.Zero,
                            FeeAddress = new UInt160(),
                            Owner      = rtx.Owner,
                            Admin      = rtx.Admin,
                            Issuer     = rtx.Admin,
                            Expiration = block.Index + 2 * 2000000,
                            IsFrozen   = false
                        });
#pragma warning restore CS0612
                }
                break;

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

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

                case TransactionType.EnrollmentTransaction:
                {
#pragma warning disable CS0612
                    EnrollmentTransaction enroll_tx = (EnrollmentTransaction)tx;
                    validators.GetOrAdd(enroll_tx.PublicKey, () => new ValidatorState
                        {
                            PublicKey = enroll_tx.PublicKey
                        });
#pragma warning restore CS0612
                }
                break;

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

                case TransactionType.InvocationTransaction:
                {
                    InvocationTransaction itx          = (InvocationTransaction)tx;
                    CachedScriptTable     script_table = new CachedScriptTable(contracts);
                    StateMachine          service      = new StateMachine(accounts, validators, assets, contracts, storages);
                    ApplicationEngine     engine       = new ApplicationEngine(TriggerType.Application, itx, script_table, service, itx.Gas);
                    engine.LoadScript(itx.Script, false);
                    if (engine.Execute())
                    {
                        service.Commit();
                        notifications.AddRange(service.Notifications);
                    }
                }
                break;
                }
            }
            if (notifications.Count > 0)
            {
                OnNotify(block, notifications.ToArray());
            }
            accounts.DeleteWhere((k, v) => !v.IsFrozen && v.Votes.Length == 0 && v.Balances.All(p => p.Value <= Fixed8.Zero));
            accounts.Commit(batch);
            unspentcoins.DeleteWhere((k, v) => v.Items.All(p => p.HasFlag(CoinState.Spent)));
            unspentcoins.Commit(batch);
            spentcoins.DeleteWhere((k, v) => v.Items.Count == 0);
            spentcoins.Commit(batch);
            validators.Commit(batch);
            assets.Commit(batch);
            contracts.Commit(batch);
            storages.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;
        }
Exemple #19
0
        private void Persist(Block block)
        {
            const int UnclaimedItemSize = sizeof(ushort) + sizeof(uint);
            MultiValueDictionary <UInt256, ushort> unspents = new MultiValueDictionary <UInt256, ushort>(p =>
            {
                Slice value;
                if (!db.TryGet(ReadOptions.Default, SliceBuilder.Begin(DataEntryPrefix.IX_Unspent).Add(p), out value))
                {
                    value = new byte[0];
                }
                return(new HashSet <ushort>(value.ToArray().GetUInt16Array()));
            });
            MultiValueDictionary <UInt256, ushort, uint> unclaimed = new MultiValueDictionary <UInt256, ushort, uint>(p =>
            {
                Slice value;
                if (!db.TryGet(ReadOptions.Default, SliceBuilder.Begin(DataEntryPrefix.IX_Unclaimed).Add(p), out value))
                {
                    value = new byte[0];
                }
                byte[] data = value.ToArray();
                return(Enumerable.Range(0, data.Length / UnclaimedItemSize).ToDictionary(i => data.ToUInt16(i * UnclaimedItemSize), i => data.ToUInt32(i * UnclaimedItemSize + sizeof(ushort))));
            });
            MultiValueDictionary <UInt256, ushort> unspent_votes = new MultiValueDictionary <UInt256, ushort>(p =>
            {
                Slice value;
                if (!db.TryGet(ReadOptions.Default, SliceBuilder.Begin(DataEntryPrefix.IX_Vote).Add(p), out value))
                {
                    value = new byte[0];
                }
                return(new HashSet <ushort>(value.ToArray().GetUInt16Array()));
            });
            Dictionary <UInt256, Fixed8> quantities = new Dictionary <UInt256, Fixed8>();
            WriteBatch batch         = new WriteBatch();
            long       amount_sysfee = GetSysFeeAmount(block.PrevBlock) + (long)block.Transactions.Sum(p => p.SystemFee);

            batch.Put(SliceBuilder.Begin(DataEntryPrefix.DATA_Header).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.Height).Add(tx.ToArray()));
                if (tx.Attributes.Any(p => p.Usage == TransactionAttributeUsage.Vote))
                {
                    unspent_votes.AddEmpty(tx.Hash);
                    for (ushort index = 0; index < tx.Outputs.Length; index++)
                    {
                        if (tx.Outputs[index].AssetId == AntShare.Hash)
                        {
                            unspent_votes.Add(tx.Hash, index);
                        }
                    }
                }
                switch (tx.Type)
                {
                case TransactionType.IssueTransaction:
                    foreach (TransactionResult result in tx.GetTransactionResults().Where(p => p.Amount < Fixed8.Zero))
                    {
                        if (quantities.ContainsKey(result.AssetId))
                        {
                            quantities[result.AssetId] -= result.Amount;
                        }
                        else
                        {
                            quantities.Add(result.AssetId, -result.Amount);
                        }
                    }
                    break;

                case TransactionType.ClaimTransaction:
                    foreach (CoinReference input in ((ClaimTransaction)tx).Claims)
                    {
                        unclaimed.Remove(input.PrevHash, input.PrevIndex);
                    }
                    break;

                case TransactionType.EnrollmentTransaction:
                {
                    EnrollmentTransaction enroll_tx = (EnrollmentTransaction)tx;
                    batch.Put(SliceBuilder.Begin(DataEntryPrefix.IX_Enrollment).Add(tx.Hash), true);
                }
                break;

                case TransactionType.PublishTransaction:
                {
                    PublishTransaction publish_tx = (PublishTransaction)tx;
                    batch.Put(SliceBuilder.Begin(DataEntryPrefix.DATA_Contract).Add(publish_tx.Code.ScriptHash), publish_tx.Code.ToArray());
                }
                break;
                }
                unspents.AddEmpty(tx.Hash);
                for (ushort index = 0; index < tx.Outputs.Length; index++)
                {
                    unspents.Add(tx.Hash, index);
                }
            }
            foreach (var group in block.Transactions.SelectMany(p => p.Inputs).GroupBy(p => p.PrevHash))
            {
                int         height;
                Transaction tx = GetTransaction(ReadOptions.Default, group.Key, out height);
                foreach (CoinReference input in group)
                {
                    if (input.PrevIndex == 0)
                    {
                        batch.Delete(SliceBuilder.Begin(DataEntryPrefix.IX_Enrollment).Add(input.PrevHash));
                    }
                    unspents.Remove(input.PrevHash, input.PrevIndex);
                    unspent_votes.Remove(input.PrevHash, input.PrevIndex);
                    if (tx?.Outputs[input.PrevIndex].AssetId == AntShare.Hash)
                    {
                        unclaimed.Add(input.PrevHash, input.PrevIndex, block.Height);
                    }
                }
            }
            foreach (var unspent in unspents)
            {
                if (unspent.Value.Count == 0)
                {
                    batch.Delete(SliceBuilder.Begin(DataEntryPrefix.IX_Unspent).Add(unspent.Key));
                }
                else
                {
                    batch.Put(SliceBuilder.Begin(DataEntryPrefix.IX_Unspent).Add(unspent.Key), unspent.Value.ToByteArray());
                }
            }
            foreach (var spent in unclaimed)
            {
                if (spent.Value.Count == 0)
                {
                    batch.Delete(SliceBuilder.Begin(DataEntryPrefix.IX_Unclaimed).Add(spent.Key));
                }
                else
                {
                    using (MemoryStream ms = new MemoryStream(spent.Value.Count * UnclaimedItemSize))
                        using (BinaryWriter w = new BinaryWriter(ms))
                        {
                            foreach (var pair in spent.Value)
                            {
                                w.Write(pair.Key);
                                w.Write(pair.Value);
                            }
                            w.Flush();
                            batch.Put(SliceBuilder.Begin(DataEntryPrefix.IX_Unclaimed).Add(spent.Key), ms.ToArray());
                        }
                }
            }
            foreach (var unspent in unspent_votes)
            {
                if (unspent.Value.Count == 0)
                {
                    batch.Delete(SliceBuilder.Begin(DataEntryPrefix.IX_Vote).Add(unspent.Key));
                }
                else
                {
                    batch.Put(SliceBuilder.Begin(DataEntryPrefix.IX_Vote).Add(unspent.Key), unspent.Value.ToByteArray());
                }
            }
            foreach (var quantity in quantities)
            {
                batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_QuantityIssued).Add(quantity.Key), (GetQuantityIssued(quantity.Key) + quantity.Value).GetData());
            }
            batch.Put(SliceBuilder.Begin(DataEntryPrefix.SYS_CurrentBlock), SliceBuilder.Begin().Add(block.Hash).Add(block.Height));
            db.Write(WriteOptions.Default, batch);
            current_block_height = block.Height;
        }
Exemple #20
0
        private void Persist(Block block)
        {
            DataCache <UInt160, AccountState>     accounts     = new DataCache <UInt160, AccountState>(db, DataEntryPrefix.ST_Account);
            DataCache <UInt256, UnspentCoinState> unspentcoins = new DataCache <UInt256, UnspentCoinState>(db, DataEntryPrefix.ST_Coin);
            DataCache <UInt256, SpentCoinState>   spentcoins   = new DataCache <UInt256, SpentCoinState>(db, DataEntryPrefix.ST_SpentCoin);
            DataCache <ECPoint, ValidatorState>   validators   = new DataCache <ECPoint, ValidatorState>(db, DataEntryPrefix.ST_Validator);
            DataCache <UInt256, AssetState>       assets       = new DataCache <UInt256, AssetState>(db, DataEntryPrefix.ST_Asset);
            DataCache <UInt160, ContractState>    contracts    = new DataCache <UInt160, ContractState>(db, DataEntryPrefix.ST_Contract);
            WriteBatch batch         = new WriteBatch();
            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()));
                switch (tx.Type)
                {
                case TransactionType.RegisterTransaction:
                {
                    RegisterTransaction rtx = (RegisterTransaction)tx;
                    assets.Add(tx.Hash, new AssetState
                        {
                            AssetId    = rtx.Hash,
                            AssetType  = rtx.AssetType,
                            Name       = rtx.Name,
                            Amount     = rtx.Amount,
                            Available  = Fixed8.Zero,
                            Precision  = rtx.Precision,
                            Fee        = Fixed8.Zero,
                            FeeAddress = new UInt160(),
                            Owner      = rtx.Owner,
                            Admin      = rtx.Admin,
                            Issuer     = rtx.Admin,
                            Expiration = block.Index + 2000000,
                            IsFrozen   = false
                        });
                }
                break;

                case TransactionType.IssueTransaction:
                    foreach (TransactionResult result in tx.GetTransactionResults().Where(p => p.Amount < Fixed8.Zero))
                    {
                        assets[result.AssetId].Available -= result.Amount;
                    }
                    break;

                case TransactionType.ClaimTransaction:
                    foreach (CoinReference input in ((ClaimTransaction)tx).Claims)
                    {
                        spentcoins.TryGet(input.PrevHash)?.Items.Remove(input.PrevIndex);
                    }
                    break;

                case TransactionType.EnrollmentTransaction:
                {
                    EnrollmentTransaction enroll_tx = (EnrollmentTransaction)tx;
                    validators.Add(enroll_tx.PublicKey, new ValidatorState
                        {
                            PublicKey = enroll_tx.PublicKey
                        });
                }
                break;

                case TransactionType.PublishTransaction:
                {
                    PublishTransaction publish_tx = (PublishTransaction)tx;
                    contracts.GetOrAdd(publish_tx.Code.ScriptHash, () => new ContractState
                        {
                            Script     = publish_tx.Code.Script,
                            HasStorage = false
                        });
                }
                break;
                }
                unspentcoins.Add(tx.Hash, new UnspentCoinState
                {
                    Items = Enumerable.Repeat(CoinState.Confirmed, tx.Outputs.Length).ToArray()
                });
                foreach (TransactionOutput output in tx.Outputs)
                {
                    AccountState account = accounts.GetOrAdd(output.ScriptHash, () => new AccountState
                    {
                        ScriptHash = output.ScriptHash,
                        IsFrozen   = false,
                        Votes      = new ECPoint[0],
                        Balances   = new Dictionary <UInt256, Fixed8>()
                    });
                    if (account.Balances.ContainsKey(output.AssetId))
                    {
                        account.Balances[output.AssetId] += output.Value;
                    }
                    else
                    {
                        account.Balances[output.AssetId] = output.Value;
                    }
                }
            }
            foreach (var group in block.Transactions.SelectMany(p => p.Inputs).GroupBy(p => p.PrevHash))
            {
                int         height;
                Transaction tx = GetTransaction(ReadOptions.Default, group.Key, out height);
                foreach (CoinReference input in group)
                {
                    unspentcoins[input.PrevHash].Items[input.PrevIndex] |= CoinState.Spent;
                    if (tx.Outputs[input.PrevIndex].AssetId.Equals(SystemShare.Hash))
                    {
                        spentcoins.GetOrAdd(input.PrevHash, () => new SpentCoinState
                        {
                            TransactionHash   = input.PrevHash,
                            TransactionHeight = (uint)height,
                            Items             = new Dictionary <ushort, uint>()
                        }).Items.Add(input.PrevIndex, block.Index);
                    }
                    accounts[tx.Outputs[input.PrevIndex].ScriptHash].Balances[tx.Outputs[input.PrevIndex].AssetId] -= tx.Outputs[input.PrevIndex].Value;
                }
            }
            accounts.DeleteWhere((k, v) => !v.IsFrozen && v.Votes.Length == 0 && v.Balances.All(p => p.Value <= Fixed8.Zero));
            accounts.Commit(batch);
            unspentcoins.DeleteWhere((k, v) => v.Items.All(p => p.HasFlag(CoinState.Spent)));
            unspentcoins.Commit(batch);
            spentcoins.DeleteWhere((k, v) => v.Items.Count == 0);
            spentcoins.Commit(batch);
            validators.Commit(batch);
            assets.Commit(batch);
            contracts.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;
        }