diff --git a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs
index 357fb9094a..1533abb887 100644
--- a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs
+++ b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs
@@ -35,6 +35,11 @@ partial class ApplicationEngine
///
public const int MaxNotificationSize = 1024;
+ ///
+ /// The maximum number of notifications per application execution.
+ ///
+ public const int MaxNotificationCount = 512;
+
private uint random_times = 0;
///
@@ -393,9 +398,16 @@ protected internal void RuntimeNotifyV1(byte[] eventName, Array state)
/// The arguments of the event.
protected internal void SendNotification(UInt160 hash, string eventName, Array state)
{
+ notifications ??= new List();
+ // Restrict the number of notifications for Application executions. Do not check
+ // persisting triggers to avoid native persist failure. Do not check verification
+ // trigger since verification context is loaded with ReadOnly flag.
+ if (IsHardforkEnabled(Hardfork.HF_Echidna) && Trigger == TriggerType.Application && notifications.Count >= MaxNotificationCount)
+ {
+ throw new InvalidOperationException($"Maximum number of notifications `{MaxNotificationCount}` is reached.");
+ }
NotifyEventArgs notification = new(ScriptContainer, hash, eventName, (Array)state.DeepCopy(asImmutable: true));
Notify?.Invoke(this, notification);
- notifications ??= new List();
notifications.Add(notification);
CurrentContext.GetState().NotificationCount++;
}