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; } }
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)); }
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)); }
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); } }
#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); } }
/// <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; }
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; }
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; }
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; }