Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
42791b5
RestServer on `dev` branch
cschuchardt88 Jul 25, 2025
7c602ae
Merge branch 'dev' into dev/add/rest-server-plugin
shargon Jul 27, 2025
f4f27ba
Merge branch 'dev' into dev/add/rest-server-plugin
shargon Jul 29, 2025
864b044
Update src/Plugins/RestServer/RestWebServer.cs
cschuchardt88 Jul 29, 2025
fd69934
Merge branch 'dev' into dev/add/rest-server-plugin
Jim8y Jul 30, 2025
c46d530
Fix ContractMethodParametersJsonConverter
shargon Jul 30, 2025
a749502
Clean ProtocolSettingsModel.cs
shargon Jul 30, 2025
28d9014
Merge branch 'dev' into dev/add/rest-server-plugin
Jim8y Jul 30, 2025
21d1c2f
Update src/Plugins/RestServer/RestWebServer.cs
cschuchardt88 Jul 30, 2025
0490605
Merge branch 'dev' into dev/add/rest-server-plugin
Wi1l-B0t Jul 31, 2025
0f2c5f3
Apply suggestions from code review
shargon Jul 31, 2025
c42ee0e
Merge branch 'dev' into dev/add/rest-server-plugin
NGDAdmin Aug 1, 2025
88ab4b2
Update src/Plugins/RestServer/Tokens/NEP17Token.cs
Jim8y Aug 2, 2025
896dbb9
Added `using` statement
cschuchardt88 Aug 3, 2025
2f4bd83
Merge branch 'dev' into dev/add/rest-server-plugin
cschuchardt88 Aug 4, 2025
3b6e41d
Merge branch 'dev' into dev/add/rest-server-plugin
NGDAdmin Aug 4, 2025
5adde99
Merge branch 'dev' into dev/add/rest-server-plugin
cschuchardt88 Aug 4, 2025
81b8bc4
Merge branch 'dev' into dev/add/rest-server-plugin
NGDAdmin Aug 4, 2025
b087ca0
Merge branch 'dev' into dev/add/rest-server-plugin
NGDAdmin Aug 5, 2025
a9e36c8
Fixed tests
cschuchardt88 Aug 5, 2025
e86b2e8
Merge branch 'dev' into dev/add/rest-server-plugin
cschuchardt88 Aug 5, 2025
fbc6c3f
Merge branch 'dev' into dev/add/rest-server-plugin
Jim8y Aug 5, 2025
98b799a
Merge branch 'dev' into dev/add/rest-server-plugin
cschuchardt88 Aug 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
108 changes: 108 additions & 0 deletions docs/RestServer/Addons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
## RestServer Plugin
In this section of you will learn how to make a `neo-cli` plugin that integrates with `RestServer`
plugin. Lets take a look at [Example Plugin](/examples/RestServerPlugin).

- No reference to `RestServer` is required.
- Requires DotNet 7.0

## Folder Structure
```bash
Project
├── Controllers
│ └── ExampleController.cs
├── ExamplePlugin.cs
├── ExamplePlugin.csproj
├── Exceptions
│ └── CustomException.cs
└── Models
└── ErrorModel.cs
```
The only thing that is important here is the `controllers` folder. This folder is required for the `RestServer`
plugin to register the controllers in its web server. This location is where you put all your controllers.

## Controllers
The `controller` class is the same as ASP.Net Core's. Controllers must have their attribute set
as `[ApiController]` and inherent from `ControllerBase`.

## Swagger Controller
A `Swagger` controller uses special attributes that are set on your controller's class.

**Controller Class Attributes**
- `[Produces(MediaTypeNames.Application.Json)]` (_Required_)
- `[Consumes(MediaTypeNames.Application.Json)]` (_Required_)
- `[ApiExplorerSettings(GroupName = "v1")]`
- **GroupName** - _is which version of the API you are targeting._
- `[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ErrorModel))]` (_Required_)
- **Type** - _Must have a base class of [error](#error-class)._

## Error Class
Needs to be the same as `RestServer` of else there will be some inconsistencies
with end users not knowing which type to use. This class can be `public` or `internal`.
Properties `Code`, `Name` and `Message` values can be whatever you desire.

**Model**
```csharp
public class ErrorModel
{
public int Code { get; set; };
public string Name { get; set; };
public string Message { get; set; };
}
```

## Controller Actions
Controller actions need to have special attributes as well as code comments.

- `[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]`

HTTP status code `200 (OK)` is required with return type defined. You can use more than one attribute. One per HTTP status code.

### Action Example
```csharp
[HttpGet("contracts/{hash:required}/sayHello", Name = "GetSayHello")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
public IActionResult GetSayHello(
[FromRoute(Name = "hash")]
UInt160 scripthash)
{
if (scripthash == UInt160.Zero)
return NoContent();
return Ok($"Hello, {scripthash}");
}
```
Notice that the _above_ example also returns with HTTP status code of `204 No Content`.
This action `route` also extends the `contracts` API. Adding method `sayHello`. Routes
can be what you like as well. But if you want to extend on any existing controller you
must use existing routes paths.

### Path(s)
- `/api/v1/contracts/`
- `/api/v1/ledger/`
- `/api/v1/node/`
- `/api/v1/tokens`
- `/api/v1/Utils/`

### Excluded Path(s)
- `/api/v1/wallet/`

_for security reasons_.

### Code Comments for Swagger
```csharp
/// <summary>
///
/// </summary>
/// <param name="" example=""></param>
/// <returns></returns>
/// <response code="200">Successful</response>
/// <response code="400">An error occurred. See Response for details.</response>
```

Also note that you need to have `GenerateDocumentationFile` enabled in your
`.csproj` file. The `xml` file that is generated; in our case would be `RestServerPlugin.xml`.
This file gets put in same directory `Plugins/RestServerPlugin/` which is in the root of `neo-node`
executable folder. Where you will see `neo-cli.exe`.

File `RestServerPlugin.xml` will get added to `Swagger` automatically by the `RestServer`
plugin.
54 changes: 54 additions & 0 deletions docs/RestServer/ConfigFile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
## Table

| Name | Type | Description |
| :--- | :---: | :--- |
|**Network**|_uint32_|_Network you would like the `RestServer` to be enabled on._|
|**BindAddress**|_string_|_Ip address of the interface you want to bind too._|
|**Port**|_uint32_|_Port number to bind too._|
|**KeepAliveTimeout**|_uint32_|_Time to keep the request alive, in seconds._|
|**SslCertFile**|_string_|_Is the path and file name of a certificate file, relative to the directory that contains the node's executable files._|
|**SslCertPassword**|_string_|_Is the password required to access the `X.509` certificate data._|
|**TrustedAuthorities**|_StringArray_|_Tumbprints of the of the last certificate authority in the chain._|
|**EnableBasicAuthentication**|_boolean_|_enables basic authentication._|
|**RestUser**|_string_|_Basic authentication's `username`._|
|**RestPass**|_string_|_Basic authentication's `password`._|
|**EnableCors**|_boolean_|_Enables Cross-origin resource sharing (`CORS`). Note by default it enables `*` any origin._|
|**AllowOrigins**|_StringArray_|_A list of the origins to allow. Note needs to add origins for basic auth to work with `CORS`._|
|**DisableControllers**|_StringArray_|_A list of `controllers` to be disabled. Requires restart of the node, if changed._|
|**EnableCompression**|_boolean_|_Enables `GZip` data compression._|
|**CompressionLevel**|_enum_|_Compression level. Values can be `Fastest`, `Optimal`, `NoCompression` or `SmallestSize`_|
|**EnableForwardedHeaders**|_boolean_|_Enables response/request headers for proxy forwarding. (data center usage)_|
|**EnableSwagger**|_boolean_|_Enables `Swagger` with `Swagger UI` for the rest services._|
|**MaxPageSize**|_uint32_|_Max page size for searches on `Ledger`/`Contracts` route._|
|**MaxConcurrentConnections**|_int64_|_Max allow concurrent HTTP connections._|
|**MaxInvokeGas**|_int64_|_Max gas to be invoked on the `Neo` virtual machine._|

## Default "Config.json" file
```json
{
"PluginConfiguration": {
"Network": 860833102,
"BindAddress": "127.0.0.1",
"Port": 10339,
"KeepAliveTimeout": 120,
"SslCertFile": "",
"SslCertPassword": "",
"TrustedAuthorities": [],
"EnableBasicAuthentication": false,
"RestUser": "",
"RestPass": "",
"EnableCors": true,
"AllowOrigins": [],
"DisableControllers": [ "WalletController" ],
"EnableCompression": true,
"CompressionLevel": "SmallestSize",
"EnableForwardedHeaders": false,
"EnableSwagger": true,
"MaxPageSize": 50,
"MaxConcurrentConnections": 40,
"MaxTransactionFee": 10000000,
"MaxInvokeGas": 20000000,
"WalletSessionTimeout": 120
}
}
```
144 changes: 144 additions & 0 deletions docs/RestServer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
## RestServer
In this section you will learn about `RestServer` plugin and how it works.

See [config.json](ConfigFile.md) for information about the configurations.

## Dependencies
- **Microsoft.AspNetCore.JsonPatch.dll** `Required`
- **Microsoft.AspNetCore.Mvc.NewtonsoftJson.dll** `Required`
- **Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer.dll** `Required`
- **Microsoft.AspNetCore.Mvc.Versioning.dll** `Required`
- **Microsoft.OpenApi.dll** `Required`
- **Newtonsoft.Json.Bson.dll** `Required`
- **Newtonsoft.Json.dll** `Required`
- **System.ServiceProcess.ServiceController.dll** `Required`
- **Microsoft.AspNetCore.Mvc.Versioning.dll** `Required`
- **Microsoft.AspNetCore.Mvc.Versioning.dll** `Required`
- **Microsoft.AspNetCore.Mvc.Versioning.dll** `Required`
- **Microsoft.OpenApi.dll** `Swagger`
- **Swashbuckle.AspNetCore.Swagger.dll** `Swagger`
- **Swashbuckle.AspNetCore.SwaggerGen.dll** `Swagger`
- **Swashbuckle.AspNetCore.SwaggerUI.dll** `Swagger`
- **Swashbuckle.AspNetCore.Newtonsoft.dll** `Swagger`
- **RestServer.xml** `Swagger UI`

These files go in the same directory as the `RestServer.dll`. In neo-cli
`plugins/RestServer/` folder.

## Response Headers
| Name | Value(s) | Description |
| :---: | --- | :--- |
|**server**|_neo-cli/3.6.0 RestServer/3.6.0_|_`neo-cli` and `RestServer` version._|

Custom headers can be added by [Neo RestServer Plugins](Addons.md).

## JSON Serializer
`RestServer` uses custom NewtonSoft JSON Converters to serialize controller action
responses and `route` parameters.

**One Way Binding** - `Write` only.
- `Neo.SmartContract.ContractState`
- `Neo.SmartContract.NefFile`
- `Neo.SmartContract.MethodToken`
- `Neo.SmartContract.Native.TrimmedBlock`
- `Neo.SmartContract.Manifest.ContractAbi`
- `Neo.SmartContract.Manifest.ContractGroup`
- `Neo.SmartContract.Manifest.ContractManifest`
- `Neo.SmartContract.Manifest.ContractPermission`
- `Neo.SmartContract.Manifest.ContractPermissionDescriptor`
- `Neo.Network.P2P.Payloads.Block`
- `Neo.Network.P2P.Payloads.Header`
- `Neo.Network.P2P.Payloads.Signer`
- `Neo.Network.P2P.Payloads.TransactionAttribute`
- `Neo.Network.P2P.Payloads.Transaction`
- `Neo.Network.P2P.Payloads.Witness`

**Two Way Binding** - `Read` & `Write`
- `System.Guid`
- `System.ReadOnlyMemory<T>`
- `Neo.BigDecimal`
- `Neo.UInt160`
- `Neo.UInt256`
- `Neo.Cryptography.ECC.ECPoint`
- `Neo.VM.Types.Array`
- `Neo.VM.Types.Boolean`
- `Neo.VM.Types.Buffer`
- `Neo.VM.Types.ByteString`
- `Neo.VM.Types.Integer`
- `Neo.VM.Types.InteropInterface`
- `Neo.VM.Types.Null`
- `Neo.VM.Types.Map`
- `Neo.VM.Types.Pointer`
- `Neo.VM.Types.StackItem`
- `Neo.VM.Types.Struct`

## Remote Endpoints
Parametes `{hash}` can be any Neo N3 address or scripthash; `{address}` can be any Neo N3 address **only**; `{number}` and `{index}` can be any _**uint32**_.

**Parameter Examples**
- `{hash}` - _0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5_ **or** _NiHURyS83nX2mpxtA7xq84cGxVbHojj5Wc_
- `{address}` - _NiHURyS83nX2mpxtA7xq84cGxVbHojj5Wc_
- `{number}` - _1_
- `{index}` - _2500000_

**Paths**
- Utils
- `[GET]` `/api/v1/utils/{hash}/address`
- `[GET]` `/api/v1/utils/{address}/scripthash`
- `[GET]` `/api/v1/utils/{hash}/{address}/validate`
- Node
- `[GET]` `/api/v1/node/peers`
- `[GET]` `/api/v1/node/plugins`
- `[GET]` `/api/v1/node/settings`
- Ledger
- `[GET]` `/api/v1/ledger/neo/accounts`
- `[GET]` `/api/v1/ledger/gas/accounts`
- `[GET]` `/api/v1/ledger/blocks?page={number}&size={number}`
- `[GET]` `/api/v1/ledger/blocks/height`
- `[GET]` `/api/v1/ledger/blocks/{index}`
- `[GET]` `/api/v1/ledger/blocks/{index}/header`
- `[GET]` `/api/v1/ledger/blocks/{index}/witness`
- `[GET]` `/api/v1/ledger/blocks/{index}/transactions?page={number}&size={number}`
- `[GET]` `/api/v1/ledger/transactions/{hash}`
- `[GET]` `/api/v1/ledger/transactions/{hash}/witnesses`
- `[GET]` `/api/v1/ledger/transactions/{hash}/signers`
- `[GET]` `/api/v1/ledger/transactions/{hash}/atributes`
- `[GET]` `/api/v1/ledger/memorypool?page={number}&size={number}`
- `[GET]` `/api/v1/ledger/memorypool/verified?page={number}&size={number}`
- `[GET]` `/api/v1/ledger/memorypool/unverified?page={number}&size={number}`
- `[GET]` `/api/v1/ledger/memorypool/count`
- Tokens
- `[GET]` `/api/v1/tokens/balanceof/{address}`
- NFTs
- `[GET]` `/api/v1/tokens/nep-11?page={number}&size={number}`
- `[GET]` `/api/v1/tokens/nep-11/count`
- `[GET]` `/api/v1/tokens/nep-11/{hash}/balanceof/{address}`
- NEP-17
- `[GET]` `/api/v1/tokens/nep-17?page={number}&size={number}`
- `[GET]` `/api/v1/tokens/nep-17/count`
- `[GET]` `/api/v1/tokens/nep-17/{hash}/balanceof/{address}`
- Contracts
- `[GET]` `/api/v1/contracts?page={number}&size={number}`
- `[GET]` `/api/v1/contracts/count`
- `[GET]` `/api/v1/contracts/{hash}`
- `[GET]` `/api/v1/contracts/{hash}/abi`
- `[GET]` `/api/v1/contracts/{hash}/manifest`
- `[GET]` `/api/v1/contracts/{hash}/nef`
- `[GET]` `/api/v1/contracts/{hash}/storage`
- Wallet
- `[POST]` `/api/v1/wallet/open`
- `[POST]` `/api/v1/wallet/create`
- `[POST]` `/api/v1/wallet/{session}/address/create`
- `[GET]` `/api/v1/wallet/{session}/address/list`
- `[GET]` `/api/v1/wallet/{session}/asset/list`
- `[GET]` `/api/v1/wallet/{session}/balance/list`
- `[POST]` `/api/v1/wallet/{session}/changepassword`
- `[GET]` `/api/v1/wallet/{session}/close`
- `[GET]` `/api/v1/wallet/{session}/delete/{address}`
- `[GET]` `/api/v1/wallet/{session}/export/{address}`
- `[GET]` `/api/v1/wallet/{session}/export`
- `[GET]` `/api/v1/wallet/{session}/gas/unclaimed`
- `[GET]` `/api/v1/wallet/{session}/key/list`
- `[POST]` `/api/v1/wallet/{session}/import`
- `[POST]` `/api/v1/wallet/{session}/import/multisigaddress`
- `[POST]` `/api/v1/wallet/{session}/transfer`
60 changes: 60 additions & 0 deletions docs/RestServer/RateLimiting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Rate Limiting in Neo REST Server

## Overview

The rate limiting feature in the Neo REST Server plugin provides protection against abuse by limiting the number of requests a client can make in a given time period. This helps maintain stability, security, and performance of the REST API.

## Configuration

Rate limiting can be configured in the `RestServer.json` file with the following options:

| Parameter | Type | Description |
|-----------|------|-------------|
| `EnableRateLimiting` | boolean | Enables or disables rate limiting |
| `RateLimitPermitLimit` | integer | Maximum number of requests allowed in the specified time window |
| `RateLimitWindowSeconds` | integer | The time window in seconds for rate limiting |
| `RateLimitQueueLimit` | integer | Number of requests to queue when limit is exceeded (0 to disable queuing) |

## Default Configuration

```json
{
"EnableRateLimiting": true,
"RateLimitPermitLimit": 10,
"RateLimitWindowSeconds": 60,
"RateLimitQueueLimit": 0
}
```

By default, the configuration allows 10 requests per minute per IP address.

## How It Works

The REST Server uses ASP.NET Core's built-in rate limiting middleware (`Microsoft.AspNetCore.RateLimiting`) to implement a fixed window rate limiter. This means:

1. Requests are tracked based on the client's IP address
2. A fixed time window (configured by `RateLimitWindowSeconds`) determines the period for counting requests
3. When the limit is reached, clients receive a 429 (Too Many Requests) response with a Retry-After header

## Response Format

When a client exceeds the rate limit, they receive:

- HTTP Status: 429 Too Many Requests
- Header: `Retry-After: [seconds]`
- Body: Error message indicating when they can try again

## Use Cases

Rate limiting is particularly useful for:

1. **Preventing API Abuse**: Limits the number of requests a user or client can make
2. **Ensuring Fair Usage**: Prevents individual clients from monopolizing server resources
3. **Protecting Resources**: Controls the number of requests to prevent server overload
4. **Enhancing Security**: Helps mitigate certain types of denial of service attacks

## Important Notes

- Rate limiting is applied at the IP address level and affects all endpoints
- If your application has legitimate high-volume needs, consider adjusting the limits accordingly
- For applications with multiple clients behind a single IP (e.g., corporate proxies), consider implementing your own rate limiting logic that takes into account application-specific identifiers
Loading
Loading