Skip to content

Commit 381a552

Browse files
Jim8yNeo Bot
authored andcommitted
Merge branch 'master-n3' into telemetry
2 parents 6205514 + 4a0b914 commit 381a552

File tree

12 files changed

+68
-13
lines changed

12 files changed

+68
-13
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@
8383
<a href='https://coveralls.io/github/neo-project/neo'>
8484
<img src='https://coveralls.io/repos/github/neo-project/neo/badge.svg' alt='Coverage Status' />
8585
</a>
86+
<a href="https://deepwiki.com/neo-project/neo">
87+
<img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki.">
88+
</a>
8689
<a href="https://github.com/neo-project/neo/blob/master/LICENSE">
8790
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License.">
8891
</a>

src/Neo/Ledger/MemoryPool.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ public int Count
117117
/// </summary>
118118
public int UnVerifiedCount => _unverifiedTransactions.Count;
119119

120+
/// <summary>
121+
/// Transaction policy validator function.
122+
/// This function will be called to validate each transaction before adding it to the pool.
123+
/// If the function returns false, the transaction will be rejected.
124+
/// </summary>
125+
public Func<Transaction, IReadOnlyStore, bool>? PolicyValidator { get; set; }
126+
120127
/// <summary>
121128
/// Initializes a new instance of the <see cref="MemoryPool"/> class.
122129
/// </summary>
@@ -307,6 +314,11 @@ internal bool CanTransactionFitInPool(Transaction tx)
307314

308315
internal VerifyResult TryAdd(Transaction tx, DataCache snapshot)
309316
{
317+
if (PolicyValidator != null)
318+
{
319+
if (!PolicyValidator(tx, snapshot)) return VerifyResult.PolicyFail;
320+
}
321+
310322
var poolItem = new PoolItem(tx);
311323

312324
if (_unsortedTransactions.ContainsKey(tx.Hash)) return VerifyResult.AlreadyInPool;

src/Neo/SmartContract/ApplicationEngine.Runtime.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ protected internal void SendNotification(UInt160 hash, string eventName, Array s
425425
/// </summary>
426426
/// <param name="hash">The hash of the specified contract. It can be set to <see langword="null"/> to get all notifications.</param>
427427
/// <returns>The notifications sent during the execution.</returns>
428-
protected internal Array GetNotifications(UInt160 hash)
428+
protected internal Array GetNotifications(UInt160? hash)
429429
{
430430
IEnumerable<NotifyEventArgs> notifications = Notifications;
431431
if (hash != null) // must filter by scriptHash

src/Neo/SmartContract/ApplicationEngine.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,8 @@ protected internal StackItem Convert(object? value)
639639
/// <returns>The converted <see cref="object"/>.</returns>
640640
protected internal object? Convert(StackItem item, InteropParameterDescriptor descriptor)
641641
{
642+
if (item.IsNull && !descriptor.IsNullable && descriptor.Type != typeof(StackItem))
643+
throw new InvalidOperationException($"The argument `{descriptor.Name}` can't be null.");
642644
descriptor.Validate(item);
643645
if (descriptor.IsArray)
644646
{
@@ -647,15 +649,24 @@ protected internal StackItem Convert(object? value)
647649
{
648650
av = Array.CreateInstance(descriptor.Type.GetElementType()!, array.Count);
649651
for (int i = 0; i < av.Length; i++)
652+
{
653+
if (array[i].IsNull && !descriptor.IsElementNullable)
654+
throw new InvalidOperationException($"The element of `{descriptor.Name}` can't be null.");
650655
av.SetValue(descriptor.Converter(array[i]), i);
656+
}
651657
}
652658
else
653659
{
654660
int count = (int)item.GetInteger();
655661
if (count > Limits.MaxStackSize) throw new InvalidOperationException();
656662
av = Array.CreateInstance(descriptor.Type.GetElementType()!, count);
657663
for (int i = 0; i < av.Length; i++)
658-
av.SetValue(descriptor.Converter(Pop()), i);
664+
{
665+
StackItem popped = Pop();
666+
if (popped.IsNull && !descriptor.IsElementNullable)
667+
throw new InvalidOperationException($"The element of `{descriptor.Name}` can't be null.");
668+
av.SetValue(descriptor.Converter(popped), i);
669+
}
659670
}
660671
return av;
661672
}

src/Neo/SmartContract/InteropParameterDescriptor.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ public class InteropParameterDescriptor
4343
/// </summary>
4444
public Func<StackItem, object?> Converter { get; }
4545

46+
public bool IsNullable { get; }
47+
48+
public bool IsElementNullable { get; }
49+
4650
/// <summary>
4751
/// Indicates whether the parameter is an enumeration.
4852
/// </summary>
@@ -85,11 +89,25 @@ internal InteropParameterDescriptor(ParameterInfo parameterInfo)
8589
: this(parameterInfo.ParameterType, parameterInfo.GetCustomAttributes<ValidatorAttribute>(true).ToArray())
8690
{
8791
Name = parameterInfo.Name;
92+
if (!parameterInfo.ParameterType.IsValueType)
93+
{
94+
var context = new NullabilityInfoContext();
95+
var info = context.Create(parameterInfo);
96+
if (info.ReadState == NullabilityState.Nullable)
97+
IsNullable = true;
98+
if (info.ElementType?.ReadState == NullabilityState.Nullable)
99+
IsElementNullable = true;
100+
}
88101
}
89102

90103
internal InteropParameterDescriptor(Type type, params ValidatorAttribute[] validators)
91104
{
92105
Type = type;
106+
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
107+
{
108+
type = type.GenericTypeArguments[0];
109+
IsNullable = true;
110+
}
93111
_validators = validators;
94112
if (IsEnum)
95113
{

src/Neo/SmartContract/Native/ContractManagement.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ private async ContractTask<ContractState> Deploy(ApplicationEngine engine, byte[
310310
/// <param name="manifest">The manifest of the contract.</param>
311311
/// <returns>The updated contract.</returns>
312312
[ContractMethod(RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)]
313-
private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest)
313+
private ContractTask Update(ApplicationEngine engine, byte[]? nefFile, byte[]? manifest)
314314
{
315315
return Update(engine, nefFile, manifest, StackItem.Null);
316316
}
@@ -324,7 +324,7 @@ private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] man
324324
/// <param name="data">The data of the contract.</param>
325325
/// <returns>The updated contract.</returns>
326326
[ContractMethod(RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)]
327-
private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest, StackItem data)
327+
private ContractTask Update(ApplicationEngine engine, byte[]? nefFile, byte[]? manifest, StackItem data)
328328
{
329329
// Require CallFlags.All flag for post-Aspidochelone transactions, ref. #2653, #2673.
330330
if (engine.IsHardforkEnabled(Hardfork.HF_Aspidochelone))

src/Neo/SmartContract/Native/FungibleToken.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,6 @@ public virtual BigInteger BalanceOf(IReadOnlyStore snapshot, UInt160 account)
131131
[ContractMethod(CpuFee = 1 << 17, StorageFee = 50, RequiredCallFlags = CallFlags.States | CallFlags.AllowCall | CallFlags.AllowNotify)]
132132
private protected async ContractTask<bool> Transfer(ApplicationEngine engine, UInt160 from, UInt160 to, BigInteger amount, StackItem data)
133133
{
134-
ArgumentNullException.ThrowIfNull(from);
135-
ArgumentNullException.ThrowIfNull(to);
136134
if (amount.Sign < 0) throw new ArgumentOutOfRangeException(nameof(amount), "cannot be negative");
137135
if (!from.Equals(engine.CallingScriptHash) && !engine.CheckWitnessInternal(from))
138136
return false;

src/Neo/SmartContract/Native/NeoToken.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey)
458458
/// <returns><see langword="true"/> if the vote is successful; otherwise, <see langword="false"/>.</returns>
459459
[ContractMethod(true, Hardfork.HF_Echidna, CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States)]
460460
[ContractMethod(Hardfork.HF_Echidna, /* */ CpuFee = 1 << 16, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)]
461-
private async ContractTask<bool> Vote(ApplicationEngine engine, UInt160 account, ECPoint voteTo)
461+
private async ContractTask<bool> Vote(ApplicationEngine engine, UInt160 account, ECPoint? voteTo)
462462
{
463463
if (!engine.CheckWitnessInternal(account)) return false;
464464
return await VoteInternal(engine, account, voteTo);

src/Neo/SmartContract/Native/Notary.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ public BigInteger BalanceOf(DataCache snapshot, UInt160 account)
220220
/// <param name="to">To Account</param>
221221
/// <returns>Whether withdrawal was successfull.</returns>
222222
[ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.All)]
223-
private async ContractTask<bool> Withdraw(ApplicationEngine engine, UInt160 from, UInt160 to)
223+
private async ContractTask<bool> Withdraw(ApplicationEngine engine, UInt160 from, UInt160? to)
224224
{
225225
if (!engine.CheckWitnessInternal(from)) return false;
226226
var receive = to is null ? from : to;

src/Neo/SmartContract/Native/StdLib.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,6 @@ private static int MemorySearch([MaxLength(MaxInputLength)] byte[] mem, byte[] v
234234
[ContractMethod(CpuFee = 1 << 6)]
235235
private static int MemorySearch([MaxLength(MaxInputLength)] byte[] mem, byte[] value, int start, bool backward)
236236
{
237-
ArgumentNullException.ThrowIfNull(value);
238237
if (backward)
239238
{
240239
return mem.AsSpan(0, start).LastIndexOf(value);
@@ -250,14 +249,12 @@ private static int MemorySearch([MaxLength(MaxInputLength)] byte[] mem, byte[] v
250249
[ContractMethod(CpuFee = 1 << 8)]
251250
private static string[] StringSplit([MaxLength(MaxInputLength)] string str, string separator)
252251
{
253-
ArgumentNullException.ThrowIfNull(separator);
254252
return str.Split(separator);
255253
}
256254

257255
[ContractMethod(CpuFee = 1 << 8)]
258256
private static string[] StringSplit([MaxLength(MaxInputLength)] string str, string separator, bool removeEmptyEntries)
259257
{
260-
ArgumentNullException.ThrowIfNull(separator);
261258
StringSplitOptions options = removeEmptyEntries ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None;
262259
return str.Split(separator, options);
263260
}

0 commit comments

Comments
 (0)