Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
210 commits
Select commit Hold shift + click to select a range
67e4975
[`ut`] 100% Coverage Trie.Get (#3952) (#3957)
NGDAdmin May 22, 2025
d3b943a
New Dockerfile, New Makefile (#3954)
superboyiii May 23, 2025
39b37b5
[`Optimize`]: command tokenizer (#3918)
Wi1l-B0t May 23, 2025
9599679
[`Add`]: Plugin Sign Client (#3950)
Wi1l-B0t May 26, 2025
8403891
[`Style`]: make the code style of `StatePlugin` more standard (#3951)
Wi1l-B0t May 26, 2025
4bd86c7
Fix BigDecimal (#3963)
shargon May 26, 2025
4f0c588
Optimize: 1. add show usage if arg not provided; 2. remove downloaded…
Wi1l-B0t May 26, 2025
a6585bb
* 100% Coverage Trie.Get (#3964)
May 27, 2025
0d1ebb0
docs: Add contribution guidelines and branch rules to README (#3960)
May 27, 2025
0a231b7
[UnitTest] - Add unit tests for BigDecimal to increase code coverage …
ajara87 May 27, 2025
0a99f61
[UnitTest] Increase unit test coverage for UInt160 and UInt256 (#3956)
ajara87 May 27, 2025
7181c93
Update devcontainer.dockerfile version (#3965)
vncoelho May 28, 2025
452f9a5
Optimzie: 1. Merge duplicated code in MainService to a LoadScript met…
Wi1l-B0t May 28, 2025
6c55def
docs: Add Neo persistence system architecture documentation (#3959)
May 29, 2025
a2cd7ef
Optimize: Remove unnecessary `stackalloc` in UInt160 and UInt256 Ser…
Wi1l-B0t May 29, 2025
2378848
[feature] Storage events (#3967)
shargon May 30, 2025
2bb8bda
Optimize: keep more exception info in UInt160.Parse and UInt256.Parse…
Wi1l-B0t Jun 2, 2025
9071acc
Change to official repo (#3977)
shargon Jun 3, 2025
142b713
Reduce cache access (#3979)
shargon Jun 5, 2025
ed1cf40
[`style`] Style MPT project (#3980)
shargon Jun 5, 2025
fb95b4a
tests: extend StdLib's unit tests (#3986)
AnnaShaleva Jun 6, 2025
ea5a56f
Style: fix some variable with underscore style (#3989)
Wi1l-B0t Jun 8, 2025
e2e62bb
Optimzie: use CommonPrefixLength instead in Trie.Put (#3990)
Wi1l-B0t Jun 8, 2025
5c8874d
Create issue-metrics.yml (#3985)
shargon Jun 10, 2025
bed8c57
Fix: Assertion arguments should be passed in the correct order (#3999)
Wi1l-B0t Jun 10, 2025
c8d1549
Fix not null reference (#3996)
shargon Jun 11, 2025
3e08ff8
Add: more exception info when throw ArgumentException (#3998)
Wi1l-B0t Jun 12, 2025
de16170
[`style`] Json decorator (#3995)
shargon Jun 12, 2025
f4e4706
MPTTrie clean (#3994)
shargon Jun 13, 2025
538e5b4
Fix: P/Invokes should not be visible (#4003)
Wi1l-B0t Jun 16, 2025
14a7c22
[Optimization] - Optimize key method (#4001)
ajara87 Jun 18, 2025
5a01a56
Fix Threading hanging with `NeoSystem` (#4005)
cschuchardt88 Jun 18, 2025
f864e8a
Style: unify json init style (#4004)
Wi1l-B0t Jun 18, 2025
0dad015
Update packages (#4006)
shargon Jun 19, 2025
1ebd85d
Restore DBFTPlugin Unit Tests (ConsensusService and Consensus Context…
vncoelho Jun 20, 2025
6d59406
Style: move MPT Benchamrk Project to benchmarks/ (#4011)
Wi1l-B0t Jun 21, 2025
6d711c0
[`improve`] nullable app logs (#4008)
shargon Jun 21, 2025
67915b2
Fix: remove FluentAssertions in notary tests (#4014)
Wi1l-B0t Jun 21, 2025
7036374
Add: SignClient Vsock support (#4002)
Wi1l-B0t Jun 23, 2025
6c7f6c4
Comments: add Exception info for numeric ops (#4021)
Wi1l-B0t Jun 25, 2025
cb56508
Isolate ApplicationEngine events (#4016)
shargon Jun 28, 2025
4790594
Cache nuget packages (#4034)
shargon Jun 30, 2025
e5229fe
Style: more standard code style for Neo.VM (#4022)
Wi1l-B0t Jun 30, 2025
6c35bf8
Optimize: more semantics description and better impl for 'TestBit(thi…
Wi1l-B0t Jun 30, 2025
852771d
Improve exception messages throughout Neo codebase (#4032)
Jun 30, 2025
0c268ea
Optimize: impl `GetLowestSetBit` by `TrailingZeroCount` if available …
Wi1l-B0t Jun 30, 2025
37d3b3b
[`style`] Style neo system (#4040)
shargon Jul 1, 2025
31dea06
Refactor MainService.Vote class (#4036)
ajara87 Jul 3, 2025
c52eb34
Doc: add document for plugin SignClient (#4049)
Wi1l-B0t Jul 6, 2025
e74abfd
[`Fix`] RcpClient Directories and Naming (#4046)
cschuchardt88 Jul 7, 2025
2943818
Optimize: no secaped char for command line input (#4044)
Wi1l-B0t Jul 7, 2025
1328bb4
Fix: tx.ToJson no 'cosigners' field (#4051)
Wi1l-B0t Jul 7, 2025
cfba43d
Fix: not matched error code if argument is null with RpcMethodWithPar…
Wi1l-B0t Jul 13, 2025
7991b5e
Renamed and Fix Properties with plugins (#4062)
cschuchardt88 Jul 13, 2025
3e63b2f
[`Add`] Indexer to EvaluationStack (#4050)
cschuchardt88 Jul 13, 2025
e37e142
Comments: Add detail description for RPC Method (#4054)
Wi1l-B0t Jul 13, 2025
c330319
[`Add`] `TryCatch` & `TryCatchThrow` Extensions (#4038)
cschuchardt88 Jul 14, 2025
a0f5ed0
Add: input cli command line with `--argument-name argument-value` (#4…
Wi1l-B0t Jul 14, 2025
5bdb4c4
Optimize: more detail for help command (#4067)
Wi1l-B0t Jul 17, 2025
5cbbcd5
Optimize: clearer parser for parameter Signers and Witnesses, and fix…
Wi1l-B0t Jul 19, 2025
6b4468d
[`Fix`] Async Ask Method (#4071)
cschuchardt88 Jul 19, 2025
c3dd619
Move `install sc` out of `ConsoleServiceBase.Run` (#4048)
Wi1l-B0t Jul 19, 2025
aa39868
[`Add`] `RandomNumberFactory` Class (#3987)
cschuchardt88 Jul 19, 2025
6126b4d
[UT] - Add unit tests in NeoSystem (#3978)
ajara87 Jul 19, 2025
e29b885
Move: Neo.Network.Rpc.RpcClient.Tests to Neo.RpcClient.Tests (#4077)
Wi1l-B0t Jul 22, 2025
a3eeb56
Add Scan for Vulnerable Dependencies (#4082)
cschuchardt88 Jul 22, 2025
be1449d
Doc: Add doc for plugin RpcServer (#4068)
Wi1l-B0t Jul 23, 2025
ea94531
Add More Descriptions in PR Template (#4083)
cschuchardt88 Jul 27, 2025
f95e3d5
Fix: no handling if `ContractNameOrHashOrId` is a native contract nam…
Wi1l-B0t Jul 27, 2025
7a84ada
optimize: More parameter type support for RpcMethod (#4085)
Wi1l-B0t Jul 27, 2025
e2fab41
UT - Add test cases for OnCommand (#4095)
ajara87 Jul 30, 2025
bccd875
Add Faun (#4097)
shargon Jul 30, 2025
01d4305
fix(cli): improve macOS leveldb error messages with dependency detail…
Jim8y Jul 31, 2025
d4f04ba
Optimize: merge RpcMethod and RpcMethodWithParams (#4074)
Wi1l-B0t Aug 1, 2025
02f4ee9
Add invokeabi command for simplified contract invocation (#4033)
Jim8y Aug 1, 2025
a61ea05
Fixed `release.yml` (#4106)
cschuchardt88 Aug 4, 2025
216a17b
Doc: Add doc for plugin RpcServer, Part-2 (#4104)
Wi1l-B0t Aug 4, 2025
356deee
update packages (#4108)
shargon Aug 4, 2025
ac1e7fc
Remove GUI (#4110)
cschuchardt88 Aug 4, 2025
69f7d7a
Fixed docker.yml (#4109)
cschuchardt88 Aug 4, 2025
1758d29
Optimize RPCClient code (#4103)
ajara87 Aug 5, 2025
bfbee17
unit-tests: Use proper 'Assert' methods (#4112)
Wi1l-B0t Aug 5, 2025
e1141a4
Optimize: use explicitly typed parameters instead of JArray in `RpcMe…
Wi1l-B0t Aug 5, 2025
42ad70f
Fix: unicode escape for cli input (#4105)
Wi1l-B0t Aug 5, 2025
c8aa869
Add RestServer Plugin (#4093)
cschuchardt88 Aug 6, 2025
ec27ab8
Add some check (#4114)
shargon Aug 6, 2025
a6d5b66
Fix. Replace RpcSendByHashOrIndexAsync comment (#4116)
ajara87 Aug 6, 2025
3c63828
Clean JsonSerializer (#4113)
shargon Aug 6, 2025
1baf431
[`Add`] IComparable, Casting to UInt160 & UInt256 (#4117)
cschuchardt88 Aug 7, 2025
62c8cf0
Allow HF in syscalls (#4119)
shargon Aug 7, 2025
257756e
unit-tests: Use proper 'Assert' methods (#4122)
Wi1l-B0t Aug 8, 2025
06ace04
Fix: avoid NullReferenceException when account not found (#4120)
Wi1l-B0t Aug 11, 2025
9a7f8d7
use StringComparison IgnoreCase instead (#4124)
Wi1l-B0t Aug 11, 2025
96d2c80
[`Add`] Protected for ApplicationEngine properties (#4123)
cschuchardt88 Aug 12, 2025
045d042
Hardfork: add Gorgon hardfork (#4128)
AnnaShaleva Aug 13, 2025
cbf5650
Optimize: use expilict type instead of JArray in RpcMethod (#4125)
Wi1l-B0t Aug 14, 2025
58051c3
Fix: some default values not matched (#4134)
Wi1l-B0t Aug 18, 2025
78e3618
Fix: More jsonrpc parameter checks for `RpcServer` (#4129)
Wi1l-B0t Aug 19, 2025
715bb20
Optimize: nullable for plugin RpcServer (#4135)
Wi1l-B0t Aug 22, 2025
89ba23b
Remove netstandard phase one (#4145)
ajara87 Aug 23, 2025
8b2a9ea
fix: out of bound exception in TestAppend (#4149)
Wi1l-B0t Aug 24, 2025
0931394
Unify extensions (#4131)
shargon Aug 24, 2025
a29922e
Remove: unnecessary json rewrite for rpc interfaces (#4148)
Wi1l-B0t Aug 25, 2025
e95dca4
UnitTests: add unit tests project for plugin StateService (#4139)
Wi1l-B0t Aug 26, 2025
bc6f34e
Optimize: use explicit type instead of JArray for plugin RpcMethods (…
Wi1l-B0t Aug 26, 2025
bdfcd66
Improve StringExtensions exception messages (#4151)
Jim8y Aug 26, 2025
e3fc3d0
Optimize #4144 (#4152)
shargon Aug 26, 2025
3ba7b14
Update `coverallsapp` (#4154)
cschuchardt88 Aug 30, 2025
d06a07d
[`Add`] Hex Encode/Decode to `StdLib` (#4150)
cschuchardt88 Sep 1, 2025
d42392b
[`Add`] GetBlockedAccounts to Policy Contract (#4147)
cschuchardt88 Sep 1, 2025
e8e410a
Style: use ThrowIfNull to check argument is null or not (#4156)
Wi1l-B0t Sep 1, 2025
fe2e37c
Remove: unnecessary benchmarks in unit test (#4158)
Wi1l-B0t Sep 2, 2025
cc946e6
Remove AllowUnsafeBlocks if no unsafe blocks (#4159)
Wi1l-B0t Sep 3, 2025
daf5993
Add: parameter nullable checking for `RpcMethod` (#4157)
Wi1l-B0t Sep 8, 2025
a998ad0
Remove: unnecessary warning disable (#4162)
Wi1l-B0t Sep 8, 2025
f5bedb3
Add: unit tests for SQLiteWallet (#4160)
Wi1l-B0t Sep 8, 2025
efcfe3c
Optimize: enable nullable for SQLiteWallet (#4163)
Wi1l-B0t Sep 9, 2025
657cac5
[`Add`] Debugger Display for Storage Items, Values & Trackables (#4155)
cschuchardt88 Sep 11, 2025
8afce40
Self Storage (#4118)
shargon Sep 11, 2025
a7bd974
Fix: avoid using obsolete AesGcm (#4165)
Wi1l-B0t Sep 12, 2025
9b85382
Optimize: reduce one memory copy in UInt160.ToString and UInt256.ToSt…
Wi1l-B0t Sep 13, 2025
07a208a
Optimize: enable nullable for TokensTracker (#4167)
Wi1l-B0t Sep 15, 2025
9004da9
enable nullable for MPTrie (#4173)
Wi1l-B0t Sep 16, 2025
5cc2cfd
Optimize: add more info when throw FormatException (#4180)
Wi1l-B0t Sep 21, 2025
e818d88
Added MemorySearch Unit Tests (#4183)
cschuchardt88 Sep 24, 2025
1c5d3b8
Fix: run without interactive in mac and linux support (#4182)
Wi1l-B0t Sep 24, 2025
d38f847
Fix: cannot load config.json if neo-cli not exsit in current dir (#4192)
Wi1l-B0t Sep 24, 2025
d7ec803
Optimize: use Property intead of Method (#4197)
Wi1l-B0t Sep 29, 2025
5dd874c
Teste missed StateService workflow tests (#4195)
vncoelho Sep 29, 2025
2e10d41
WhiteListed Fee definition
shargon Oct 1, 2025
1b1d563
Rename
shargon Oct 1, 2025
5670d9d
Update src/Neo/SmartContract/Native/PolicyContract.cs
shargon Oct 2, 2025
d180196
Replaced `Random` with `RandomNumberFactory` (#4184)
cschuchardt88 Oct 4, 2025
bf73d6e
Updated `nuget` README.md (#4209)
cschuchardt88 Oct 4, 2025
0938348
Fix ut CheckNextBytes (#4210)
ajara87 Oct 4, 2025
363d730
Ceiling Divide BigInteger extension (#4208)
shargon Oct 4, 2025
3692bd3
Map constructor (#4207)
shargon Oct 4, 2025
ae044ef
Merge branch 'dev' into whitelisted-fee-definition
ajara87 Oct 5, 2025
5321dfe
Create constructor for JObject (#4206)
shargon Oct 6, 2025
ce4894e
Merge branch 'dev' into whitelisted-fee-definition
shargon Oct 6, 2025
b7b387e
Apply suggestions from code review
shargon Oct 7, 2025
4febfb2
Update src/Neo/SmartContract/Native/PolicyContract.cs
shargon Oct 7, 2025
d6be6e0
Use Interoperable and check UpdateCounter
shargon Oct 7, 2025
d0bcc5e
Optimize: sampling peers ramdomly (#4212)
Wi1l-B0t Oct 10, 2025
3e401e7
Merge branch 'dev' into whitelisted-fee-definition
ajara87 Oct 11, 2025
07ea7fa
Doc: add seriliazation format discription (#4203)
Wi1l-B0t Oct 11, 2025
9f148d6
Fixed math divide ceiling (#4211)
cschuchardt88 Oct 11, 2025
28e5ab3
Use raw key
shargon Oct 13, 2025
451c5e9
Merge branch 'dev' into whitelisted-fee-definition
shargon Oct 13, 2025
2bb4090
WhiteList effective
shargon Oct 13, 2025
d9b80e2
Merge branch 'whitelisted-fee-definition' of https://github.com/neo-p…
shargon Oct 13, 2025
4ba1439
Style: fix underline variable naming style (#4200)
Wi1l-B0t Oct 13, 2025
6ffece3
Doc: add doc for native contract API (#4220)
Wi1l-B0t Oct 13, 2025
58125f2
Add: more info to get why throw FormatException (#4215)
Wi1l-B0t Oct 13, 2025
146e81e
Doc: rpc method descriptions from other plugins (#4222)
Wi1l-B0t Oct 14, 2025
8fb2bd4
Merge branch 'dev' into whitelisted-fee-definition
Jim8y Oct 14, 2025
a70d254
Erik's review
shargon Oct 14, 2025
ee6ed70
[`Add`] Multi-Sig Support in Wallets (#4213)
cschuchardt88 Oct 15, 2025
e4e15f1
Merge branch 'dev' into whitelisted-fee-definition
shargon Oct 15, 2025
d118892
Fix ut
shargon Oct 15, 2025
0f853fc
[`Fix`] Random Factory `NextBigInteger` (#4146)
cschuchardt88 Oct 17, 2025
4246cc0
Merge branch 'dev' into whitelisted-fee-definition
erikzhang Oct 18, 2025
ba34663
Gas test suite (#4229)
shargon Oct 18, 2025
6043033
Erik's review
shargon Oct 18, 2025
6293230
Merge branch 'dev' into whitelisted-fee-definition
shargon Oct 18, 2025
73fd379
Use `GetAndChange`
shargon Oct 18, 2025
d5517eb
Replace `RotateLeft` extension with `dotnet` one (#4232)
cschuchardt88 Oct 20, 2025
db6dd64
Check fixedFee negative and unit test (#4233)
ajara87 Oct 20, 2025
272af62
[`Move`] Internals to Project File (#4231)
cschuchardt88 Oct 20, 2025
55b7c94
Merge branch 'dev' into whitelisted-fee-definition
shargon Oct 20, 2025
a5b47d2
Avoid nullable type
shargon Oct 20, 2025
fe5c745
UT-Add some UT to WhiteListedFeeUnitTests (#4234)
ajara87 Oct 21, 2025
b4d69e0
Superboy's review
shargon Oct 21, 2025
a3ef31f
Merge branch 'whitelisted-fee-definition' of https://github.com/neo-p…
shargon Oct 21, 2025
f83b9f1
update md
shargon Oct 21, 2025
1b8560e
Fix native whitelist
shargon Oct 21, 2025
72eab3b
Add: script to run localnet nodes (#4199)
Wi1l-B0t Oct 23, 2025
d7c87fa
Merge branch 'dev' into whitelisted-fee-definition
ajara87 Oct 23, 2025
455e17a
Fix: Log stacktrace to get where/why the exception is thrown (#4242)
Wi1l-B0t Oct 23, 2025
7345a68
[`Add`] Plugin Loading (#4225)
cschuchardt88 Oct 23, 2025
8fd4361
Merge branch 'dev' into whitelisted-fee-definition
shargon Oct 23, 2025
d7e9a6b
Anna's suggestion
shargon Oct 23, 2025
26345ca
Merge branch 'whitelisted-fee-definition' of https://github.com/neo-p…
shargon Oct 23, 2025
e491c3d
Update src/Neo/SmartContract/Native/PolicyContract.cs
shargon Oct 23, 2025
98e3c63
fix ut
shargon Oct 23, 2025
394bca5
Fix native contract API test path resolution (#4243)
Jim8y Oct 23, 2025
423fc99
Merge branch 'dev' into whitelisted-fee-definition
ajara87 Oct 23, 2025
d5f54ed
Fix: null reference exception on start (#4244)
Wi1l-B0t Oct 24, 2025
3923ad6
Don't allow 0 now
shargon Oct 24, 2025
12e634b
Merge branch 'dev' into whitelisted-fee-definition
shargon Oct 24, 2025
b08d5b6
Fix Ut with 1
shargon Oct 24, 2025
30aaa45
Revert min change
shargon Oct 24, 2025
e23feeb
P2P: send ArchivalNode capability, fix #2346 (#4245)
roman-khimov Oct 24, 2025
aef6f4d
Fix unit tests (#4249)
shargon Oct 25, 2025
4e4b25d
Merge branch 'dev' into whitelisted-fee-definition
ajara87 Oct 26, 2025
4d8e19b
Apply suggestions from code review
shargon Oct 27, 2025
7b58eb7
Update src/Neo/SmartContract/Native/PolicyContract.cs
shargon Oct 27, 2025
b9c6438
Add: assert committe info to get what kind of InvalidOperation for te…
Wi1l-B0t Oct 28, 2025
bee0a76
Merge branch 'dev' into whitelisted-fee-definition
shargon Oct 28, 2025
557b6c9
Update native contracts api
shargon Oct 28, 2025
f3b8170
Fix update native api (#4257)
shargon Oct 29, 2025
ceb7cda
Merge branch 'dev' into whitelisted-fee-definition
shargon Oct 29, 2025
426c81a
Added explicit Faun dependency
shargon Oct 29, 2025
1b5bb68
Emit event when clean
shargon Oct 29, 2025
4ab5033
Handle P2P handshake before ChannelsConfig (#4248)
Jim8y Nov 1, 2025
17a0c32
Fix: unexpected log source from akka (#4264)
Wi1l-B0t Nov 2, 2025
c5c3eb6
Merge branch 'master' into dev
erikzhang Nov 2, 2025
10229de
Merge branch 'dev' into whitelisted-fee-definition
Wi1l-B0t Nov 2, 2025
f5fb8b2
Merge branch 'master' into whitelisted-fee-definition
vncoelho Nov 2, 2025
2093d06
Merge branch 'master' into whitelisted-fee-definition
shargon Nov 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/native-contracts-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ When calling a native contract method by transaction script, there are several t
| getAttributeFee | Gets the fee for attribute before Echidna hardfork. NotaryAssisted attribute type not supported. | Byte(*attributeType*) | UInt32 | 1<<15 | 0 | ReadStates | Deprecated in HF_Echidna |
| getAttributeFee | Gets the fee for attribute after Echidna hardfork. NotaryAssisted attribute type supported. | Byte(*attributeType*) | UInt32 | 1<<15 | 0 | ReadStates | HF_Echidna |
| isBlocked | Determines whether the specified account is blocked. | UInt160(*account*) | Boolean | 1<<15 | 0 | ReadStates | -- |
| removeWhitelistFeeContract | Remove whitelisted Fee contracts | UInt160(*contractHash*), String(*method*), Int32(*argCount*) | Void | 1<<15 | 0 | States,AllowNotify | HF_Faun |
| setWhitelistFeeContract | Set whitelisted Fee contracts | UInt160(*contractHash*), String(*method*), Int32(*argCount*), Int64(*fixedFee*) | Void | 1<<15 | 0 | States,AllowNotify | HF_Faun |
| setMillisecondsPerBlock | Sets the block generation time in milliseconds. | UInt32(*value*) | Void | 1<<15 | 0 | States,AllowNotify | HF_Echidna |
| setAttributeFee | Sets the fee for attribute before Echidna hardfork. NotaryAssisted attribute type not supported. | Byte(*attributeType*), UInt32(*value*) | Void | 1<<15 | 0 | States | Deprecated in HF_Echidna |
| setAttributeFee | Sets the fee for attribute after Echidna hardfork. NotaryAssisted attribute type supported. | Byte(*attributeType*), UInt32(*value*) | Void | 1<<15 | 0 | States | HF_Echidna |
Expand All @@ -168,6 +170,7 @@ When calling a native contract method by transaction script, there are several t
| blockAccount | -- | UInt160(*account*) | Boolean | 1<<15 | 0 | States | -- |
| unblockAccount | -- | UInt160(*account*) | Boolean | 1<<15 | 0 | States | -- |
| getBlockedAccounts | -- | -- | StorageIterator | 1<<15 | 0 | ReadStates | HF_Faun |
| getWhitelistFeeContracts | -- | -- | StorageIterator | 1<<15 | 0 | ReadStates | HF_Faun |


## RoleManagement
Expand Down
21 changes: 19 additions & 2 deletions src/Neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,14 @@ protected static void OnSysCall(ExecutionEngine engine, Instruction instruction)
/// <param name="datoshi">The amount of GAS, in the unit of datoshi, 1 datoshi = 1e-8 GAS, to be added.</param>
protected internal void AddFee(long datoshi)
{
// Check whitelist

if (CurrentContext?.GetState<ExecutionContextState>()?.WhiteListed == true)
{
// The execution is whitelisted
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we still need to AddFee here, to make sure we still get correct maximum GAS fee per block.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it's free why we need to check the max fee per block? you propose to have two counters? free and paid?

Copy link
Contributor

@Jim8y Jim8y Oct 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shargon , casue if we dont count the actual gas cost, attacker may use whitelist contract as the DOS attack entry point. Free tranasction should still be counted how much resource it uses, to avoid too much trasnaction being added. Its just a suggestion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Jim8y I have been thinking about this because it seemed like a good idea to me, but .... I think it cannot be done since the consensus calculated the transaction fee based on signed transaction attributes and the consensus does not execute the transaction to know how much free fee it had, so at the time of deciding which transactions go in the block, that value is not available even if we had it in the application engine.

}

#pragma warning disable CS0618 // Type or member is obsolete
FeeConsumed = GasConsumed = checked(FeeConsumed + datoshi);
#pragma warning restore CS0618 // Type or member is obsolete
Expand Down Expand Up @@ -341,12 +349,21 @@ private ExecutionContext CallContractInternal(ContractState contract, ContractMe
else
{
var executingContract = IsHardforkEnabled(Hardfork.HF_Domovoi)
? state.Contract // use executing contract state to avoid possible contract update/destroy side-effects, ref. https://github.com/neo-project/neo/pull/3290.
: NativeContract.ContractManagement.GetContract(SnapshotCache, CurrentScriptHash);
? state.Contract // use executing contract state to avoid possible contract update/destroy side-effects, ref. https://github.com/neo-project/neo/pull/3290.
: NativeContract.ContractManagement.GetContract(SnapshotCache, CurrentScriptHash);
if (executingContract?.CanCall(contract, method.Name) == false)
throw new InvalidOperationException($"Cannot Call Method {method.Name} Of Contract {contract.Hash} From Contract {CurrentScriptHash}");
}

// Check whitelist

if (IsHardforkEnabled(Hardfork.HF_Faun) &&
NativeContract.Policy.IsWhitelistFeeContract(SnapshotCache, contract.Hash, method.Name, method.Parameters.Length, out var fixedFee))
{
AddFee(fixedFee.Value);
state.WhiteListed = true;
}

if (invocationCounter.TryGetValue(contract.Hash, out var counter))
{
invocationCounter[contract.Hash] = counter + 1;
Expand Down
5 changes: 5 additions & 0 deletions src/Neo/SmartContract/ExecutionContextState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,10 @@ public class ExecutionContextState
public int NotificationCount { get; set; }

public bool IsDynamicCall { get; set; }

/// <summary>
/// True if the execution is whitelisted by committee
/// </summary>
public bool WhiteListed { get; set; } = false;
}
}
6 changes: 4 additions & 2 deletions src/Neo/SmartContract/Manifest/ContractAbi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,10 @@ public ContractMethodDescriptor GetMethod(string name, int pcount)
if (pcount >= 0)
{
methodDictionary ??= Methods.ToDictionary(p => (p.Name, p.Parameters.Length));
methodDictionary.TryGetValue((name, pcount), out var method);
return method;
if (methodDictionary.TryGetValue((name, pcount), out var method))
return method;

return null;
}
else
{
Expand Down
5 changes: 5 additions & 0 deletions src/Neo/SmartContract/Native/ContractManagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,11 @@ private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] man
}
Helper.Check(new Script(contract.Nef.Script, engine.IsHardforkEnabled(Hardfork.HF_Basilisk)), contract.Manifest.Abi);
contract.UpdateCounter++; // Increase update counter

// Clean whitelist (emit event if exists)

Policy.CleanWhitelist(engine, contract.Hash);

return OnDeployAsync(engine, contract, data, true);
}

Expand Down
16 changes: 14 additions & 2 deletions src/Neo/SmartContract/Native/NativeContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,9 @@ protected static void AssertCommittee(ApplicationEngine engine)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private protected StorageKey CreateStorageKey(byte prefix, UInt256 hash, UInt160 signer) => StorageKey.Create(Id, prefix, hash, signer);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private protected StorageKey CreateStorageKey(byte prefix, UInt160 hash, string methodName, int bigEndianKey) => StorageKey.Create(Id, prefix, hash, methodName, bigEndianKey);

#endregion

/// <summary>
Expand Down Expand Up @@ -435,8 +438,17 @@ internal async void Invoke(ApplicationEngine engine, byte version)
var state = context.GetState<ExecutionContextState>();
if (!state.CallFlags.HasFlag(method.RequiredCallFlags))
throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}.");
// In the unit of datoshi, 1 datoshi = 1e-8 GAS
engine.AddFee(method.CpuFee * engine.ExecFeeFactor + method.StorageFee * engine.StoragePrice);
// Check native-whitelist
if (engine.IsHardforkEnabled(Hardfork.HF_Faun) && Policy.IsWhitelistFeeContract(engine.SnapshotCache, Hash, method.Name, method.Parameters.Length, out var fixedFee))
{
// Whitelisted In the unit of datoshi, 1 datoshi = 1e-8 GAS
engine.AddFee(fixedFee.Value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this implementation might be wrong. NativeContract.Invoke cannot be called directly. It can only be called by Contract.Call. So there might be a double charge here.

}
else
{
// In the unit of datoshi, 1 datoshi = 1e-8 GAS
engine.AddFee(method.CpuFee * engine.ExecFeeFactor + method.StorageFee * engine.StoragePrice);
}
List<object> parameters = new();
if (method.NeedApplicationEngine) parameters.Add(engine);
if (method.NeedSnapshot) parameters.Add(engine.SnapshotCache);
Expand Down
131 changes: 131 additions & 0 deletions src/Neo/SmartContract/Native/PolicyContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@

#pragma warning disable IDE0051

using Neo.Extensions;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract.Iterators;
using System;
using System.Buffers.Binary;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;

namespace Neo.SmartContract.Native
Expand Down Expand Up @@ -83,6 +86,7 @@ public sealed class PolicyContract : NativeContract
public const uint MaxMaxTraceableBlocks = 2102400;

private const byte Prefix_BlockedAccount = 15;
internal const byte Prefix_WhitelistedFeeContracts = 16;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why internal?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it's used by UT

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be private. You can recalculate this value in UT.

private const byte Prefix_FeePerByte = 10;
private const byte Prefix_ExecFeeFactor = 18;
private const byte Prefix_StoragePrice = 19;
Expand All @@ -103,10 +107,18 @@ public sealed class PolicyContract : NativeContract
/// </summary>
private const string MillisecondsPerBlockChangedEventName = "MillisecondsPerBlockChanged";

private const string WhitelistChangedEventName = "WhitelistChanged";

[ContractEvent(Hardfork.HF_Echidna, 0, name: MillisecondsPerBlockChangedEventName,
"old", ContractParameterType.Integer,
"new", ContractParameterType.Integer
)]
[ContractEvent(Hardfork.HF_Faun, 1, name: WhitelistChangedEventName,
"contract", ContractParameterType.Hash160,
"method", ContractParameterType.String,
"argCount", ContractParameterType.Integer,
"fee", ContractParameterType.Any
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fee is ContractParameterType.Any?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it can be null in RemoveWhitelistFeeContract

)]
internal PolicyContract() : base()
{
_feePerByte = CreateStorageKey(Prefix_FeePerByte);
Expand Down Expand Up @@ -258,6 +270,114 @@ public bool IsBlocked(IReadOnlyStore snapshot, UInt160 account)
return snapshot.Contains(CreateStorageKey(Prefix_BlockedAccount, account));
}

internal bool IsWhitelistFeeContract(DataCache snapshot, UInt160 contractHash, string method, int argCount, [NotNullWhen(true)] out long? fixedFee)
{
// Check contract existence

var currentContract = ContractManagement.GetContract(snapshot, contractHash);

if (currentContract != null)
{
// Check state existence

var item = snapshot.TryGet(CreateStorageKey(Prefix_WhitelistedFeeContracts, contractHash, method, argCount));

if (item != null)
{
fixedFee = (long)(BigInteger)item;
return true;
}
}

fixedFee = null;
return false;
}

/// <summary>
/// Remove whitelisted Fee contracts
/// </summary>
/// <param name="engine">The execution engine.</param>
/// <param name="contractHash">The contract to set the whitelist</param>
/// <param name="method">Method</param>
/// <param name="argCount">Argument count</param>
[ContractMethod(Hardfork.HF_Faun, CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)]
private void RemoveWhitelistFeeContract(ApplicationEngine engine, UInt160 contractHash, string method, int argCount)
{
if (!CheckCommittee(engine)) throw new InvalidOperationException("Invalid committee signature");

var key = CreateStorageKey(Prefix_WhitelistedFeeContracts, contractHash, method, argCount);

if (!engine.SnapshotCache.Contains(key)) throw new InvalidOperationException("Whitelist not found");

engine.SnapshotCache.Delete(key);

// Emit event
engine.SendNotification(Hash, WhitelistChangedEventName,
[new VM.Types.ByteString(contractHash.ToArray()), new VM.Types.ByteString(method.ToStrictUtf8Bytes()),
new VM.Types.Integer(argCount), VM.Types.StackItem.Null]);
}

internal int CleanWhitelist(ApplicationEngine engine, UInt160 contractHash)
{
var count = 0;
var searchKey = CreateStorageKey(Prefix_WhitelistedFeeContracts, contractHash);

foreach ((var key, _) in engine.SnapshotCache.Find(searchKey, SeekDirection.Forward))
{
engine.SnapshotCache.Delete(key);
count++;

// Emit event recovering the values from the Key

var keyData = key.ToArray().AsSpan();
var argCount = BinaryPrimitives.ReadInt32BigEndian(keyData.Slice(StorageKey.UInt160Length, 4));
var method = keyData[(StorageKey.UInt160Length + 4)..];

engine.SendNotification(Hash, WhitelistChangedEventName,
[new VM.Types.ByteString(contractHash.ToArray()), new VM.Types.ByteString(method.ToArray()),
new VM.Types.Integer(argCount), VM.Types.StackItem.Null]);
}

return count;
}

/// <summary>
/// Set whitelisted Fee contracts
/// </summary>
/// <param name="engine">The execution engine.</param>
/// <param name="contractHash">The contract to set the whitelist</param>
/// <param name="method">Method</param>
/// <param name="argCount">Argument count</param>
/// <param name="fixedFee">Fixed execution fee</param>
[ContractMethod(Hardfork.HF_Faun, CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)]
internal void SetWhitelistFeeContract(ApplicationEngine engine, UInt160 contractHash, string method, int argCount, long fixedFee)
{
ArgumentOutOfRangeException.ThrowIfNegative(fixedFee, nameof(fixedFee));

if (!CheckCommittee(engine)) throw new InvalidOperationException("Invalid committee signature");

var key = CreateStorageKey(Prefix_WhitelistedFeeContracts, contractHash, method, argCount);

// Validate methods
var contract = ContractManagement.GetContract(engine.SnapshotCache, contractHash)
?? throw new InvalidOperationException("Is not a valid contract");

if (contract.Manifest.Abi.GetMethod(method, argCount) == null)
throw new InvalidOperationException($"{method} with {argCount} args is not a valid method of {contractHash}");

// Set
var entry = engine.SnapshotCache
.GetAndChange(key, () => new StorageItem(fixedFee));

entry.Set(fixedFee);

// Emit event

engine.SendNotification(Hash, WhitelistChangedEventName,
[new VM.Types.ByteString(contractHash.ToArray()), new VM.Types.ByteString(method.ToStrictUtf8Bytes()),
new VM.Types.Integer(argCount), new VM.Types.Integer(fixedFee)]);
}

/// <summary>
/// Sets the block generation time in milliseconds.
/// </summary>
Expand Down Expand Up @@ -438,5 +558,16 @@ private StorageIterator GetBlockedAccounts(DataCache snapshot)
.GetEnumerator();
return new StorageIterator(enumerator, 1, options);
}

[ContractMethod(Hardfork.HF_Faun, CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)]
internal StorageIterator GetWhitelistFeeContracts(DataCache snapshot)
{
const FindOptions options = FindOptions.RemovePrefix | FindOptions.KeysOnly;
var enumerator = snapshot
.Find(CreateStorageKey(Prefix_WhitelistedFeeContracts), SeekDirection.Forward)
.GetEnumerator();

return new StorageIterator(enumerator, 1, options);
}
}
}
27 changes: 26 additions & 1 deletion src/Neo/SmartContract/StorageKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;

namespace Neo.SmartContract
{
Expand Down Expand Up @@ -76,7 +77,7 @@ public int Length
private const int ByteLength = PrefixLength + sizeof(byte);
private const int Int32Length = PrefixLength + sizeof(int);
private const int Int64Length = PrefixLength + sizeof(long);
private const int UInt160Length = PrefixLength + UInt160.Length;
internal const int UInt160Length = PrefixLength + UInt160.Length;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why internal?

private const int UInt256Length = PrefixLength + UInt256.Length;
private const int UInt256UInt160Length = PrefixLength + UInt256.Length + UInt160.Length;

Expand Down Expand Up @@ -183,6 +184,30 @@ public static StorageKey Create(int id, byte prefix, UInt256 hash, UInt160 signe
return new(id, data);
}

/// <summary>
/// Create StorageKey
/// </summary>
/// <param name="id">The id of the contract.</param>
/// <param name="prefix">The prefix of the key.</param>
/// <param name="hash">Hash</param>
/// <param name="methodName">Method Name</param>
/// <param name="bigEndian">Big Endian key.</param>
/// <returns>The <see cref="StorageKey"/> class</returns>
public static StorageKey Create(int id, byte prefix, UInt160 hash, string methodName, int bigEndian)
{
const int HashAndInt = UInt160Length + sizeof(int);

var methodData = Encoding.UTF8.GetBytes(methodName);
var data = new byte[HashAndInt + methodData.Length];

FillHeader(data, id, prefix);
hash.Serialize(data.AsSpan(PrefixLength..));
BinaryPrimitives.WriteInt32BigEndian(data.AsSpan(UInt160Length..), bigEndian);
Array.Copy(methodData, 0, data, HashAndInt, methodData.Length);

return new(id, data);
}

/// <summary>
/// Create StorageKey
/// </summary>
Expand Down
20 changes: 20 additions & 0 deletions tests/Neo.UnitTests/Ledger/UT_StorageKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
using Neo.Extensions;
using Neo.SmartContract;
using System;
using System.Buffers.Binary;
using System.Text;

namespace Neo.UnitTests.Ledger
{
Expand Down Expand Up @@ -76,6 +78,24 @@ public void SameTest()
UInt256.Parse("0x761a9bb72ca2a63984db0cc43f943a2a25e464f62d1a91114c2b6fbbfd24b51d"),
UInt160.Parse("2d3b96ae1bcc5a585e075e3b81920210dec16302")).ToArray());

// UInt160+String+Int
key = new KeyBuilder(1, 2);
key.Add(UInt160.Parse("2d3b96ae1bcc5a585e075e3b81920210dec16302"));
key.AddBigEndian((int)3); // arg count
key.Add(Encoding.UTF8.GetBytes("hello world"));

CollectionAssert.AreEqual(key.ToArray(), StorageKey.Create(1, 2,
UInt160.Parse("2d3b96ae1bcc5a585e075e3b81920210dec16302"), "hello world", 3).ToArray());

// Recover method and arg count

var keyB = new StorageKey(key.ToArray()).ToArray().AsSpan();
var argCount = BinaryPrimitives.ReadInt32BigEndian(keyB.Slice(StorageKey.UInt160Length, 4));
var method = keyB[(StorageKey.UInt160Length + 4)..];

Assert.AreEqual(3, argCount);
Assert.AreEqual("hello world", Encoding.UTF8.GetString(method));

// ISerializable
key = new KeyBuilder(1, 2);
key.Add(ECCurve.Secp256r1.G);
Expand Down
Loading