Skip to content

Commit

Permalink
[rest gateway] - Align rest api to GatewayAPI + RestAPI rust wrapper…
Browse files Browse the repository at this point in the history
… + Lot of refactoring (MystenLabs#1123)

* made bytes encoding consistent - encoding IDs with Hex and data bytes with Base64
* added split-coin end point
* added merge-coin end point
* new `RestGatewayClient` - a rust wrapper for the RestAPI
* add support of Rest gateway to the wallet - wallet can be configured to connect to the network directly, or via the rest gateway
* removed start/stop/genesis from rest server
* removed wallet functionalities from rest server
* Genesis now creates a new `gateway.conf`, which can be used to start the rest gateway server.
* CORS can be configured using env variable e.g. `ACCESS_CONTROL_ALLOW_ORIGIN=* ./rest_server`
  • Loading branch information
patrickkuo authored Apr 5, 2022
1 parent d755dad commit 7c30c0a
Show file tree
Hide file tree
Showing 24 changed files with 1,245 additions and 1,346 deletions.
175 changes: 71 additions & 104 deletions doc/src/build/rest-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ Full [API documentation](https://app.swaggerhub.com/apis/MystenLabs/sui-api) can
be found on SwaggerHub.

## Local REST server setup

Follow the instructions to [install Sui binaries](install.md).

### Start local Sui Network
Follow the instructions to [create](wallet.md#genesis) and [start](wallet.md#starting-the-network) the Sui network.
The genesis process will create a `gateway.conf` configuration file, which will be used by the REST server.

### Start local REST server

Use the following command to start a local server:
Expand All @@ -21,59 +24,23 @@ rest_server
```
You will see output resembling:
```
INFO listening, local_addr: 127.0.0.1:5000
INFO listening, local_addr: 127.0.0.1:5001
```

NOTE: For additional logs, set `RUST_LOG=debug` before invoking `rest_server`

Export a local user variable to store the hardcoded hostname + port that the local REST server starts with to be used when issuing the curl commands that follow.
```shell
export SUI_GATEWAY_HOST=http://127.0.0.1:5000
export SUI_GATEWAY_HOST=http://127.0.0.1:5001
```

To initialize and start the network, you need to invoke the /sui/genesis and /sui/start endpoints as mentioned below.

## Sui REST API

In the following sections we will show how to use Sui's REST API using
the `curl` command. You can also access it using
[Postman](https://www.postman.com/) which we describe in the [Postman
setup section](#postman-setup).

## Sui network endpoints

### POST /sui/genesis

The `genesis` command creates Sui's initial state including four authorities and five user accounts
each with five gas objects:

```shell
curl --location --request POST $SUI_GATEWAY_HOST/sui/genesis | json_pp
```

These are Sui [objects](objects.md) used
to pay for Sui [transactions](transactions.md#transaction-metadata),
such as object transfers or smart contract (Move) calls.

### POST /sui/stop

The `stop` commands kills the authorities and all of the data stored in the network:

```shell
curl --location --request POST $SUI_GATEWAY_HOST/sui/stop
```

Use this if you want to reset the state of the network without having to kill the
REST server.

### POST /sui/start

The `start` command starts the Sui network with the genesis configuration specified:

```shell
curl --location --request POST $SUI_GATEWAY_HOST/sui/start | json_pp
```

## Sui endpoints

### GET /docs
Expand All @@ -84,63 +51,31 @@ Retrieve OpenAPI documentation:
curl --location --request GET $SUI_GATEWAY_HOST/docs | json_pp
```

### GET /addresses

Retrieve all managed addresses for this client:

```shell
curl --location --request GET $SUI_GATEWAY_HOST/addresses | json_pp
```

The output of this API call should include a list of five addresses
representing five user accounts created during Sui
[genesis](#post-suigenesis). Please note that actual numbers you will
see are going to be different than what is presented in this document,
as account addresses, object IDs, etc. are generated randomly during
Sui genesis. Consequently, **do not copy and paste the actual values
from this tutorial as they are unlikely to work for you verbatim.**
All that being said, part of the output should resemble the following:

```shell
{
"addresses" : [
"8C8280935E3BFDA6B48678A7D54E5FD8CA8A9E90",
"0480D08F1E05D0D8783BFA8D512375DA8BAAE296",
"084889A127487548D113CFCF4B2FAB05E572948E",
"A177CCFA2A79ED340C7046315D70936C1BC048EF",
"938AEEF943108FB80C183C56FC98DFB0D1D5147D"
]
}
```


### GET /objects
### GET /api/objects

Return the list of objects owned by an address:
```shell
curl --location --request GET $SUI_GATEWAY_HOST'/objects?address={{address}}' | json_pp
curl --location --request GET $SUI_GATEWAY_HOST'/api/objects?address={{address}}' | json_pp
```

You should replace `{{address}}` in the command above with an actual
address value, for example one obtained from [`GET
/addresses`](#get-addresses) (without quotes).
address value, you can retrieve the list of the addresses created during
genesis from `wallet.conf`.

The output you see should resemble the following (abbreviated to show only two objects):

```shell
{
"objects" : [
{
"objType" : "0x2::Coin::Coin<0x2::GAS::GAS>",
"objectDigest" : "o#3eda7d747374e1cb91921b1d4bd280fa557c7da17cfee364028f07adc20a7965",
"objectId" : "2AA11F96C434880B6D49FFEBFCA8906BA0338495",
"version" : "SequenceNumber(0)"
"digest" : "0X4CjesLYhfXITheZHEasvmQXYrk92lvhUkxF7cKhvU=",
"objectId" : "75c660b4e115aa312b56d0e46898a1673a4649f3",
"version" : 0
},
{
"objType" : "0x2::Coin::Coin<0x2::GAS::GAS>",
"objectDigest" : "o#d78e46c4e7866f8fd87883bd48e64e53c6e1d63c3314ab1aab3af7671043e363",
"objectId" : "5D4D8CA4F3E0882A6180E6B8D5903CAB814C2C9B",
"version" : "SequenceNumber(0)"
"digest" : "zgfZRhRIzYGbadG3vYuF2I8MPDPPoJuEfEbj4nnW9hY=",
"objectId" : "84fb76c2ed58021ffdef956d9a6fd63852b2506d",
"version" : 0
},
...
}
Expand All @@ -151,7 +86,7 @@ The output you see should resemble the following (abbreviated to show only two o
Return the object information for a specified object, for example:
```shell
curl --location --request GET $SUI_GATEWAY_HOST'/object_info?objectId={{object_id}}' | json_pp
curl --location --request GET $SUI_GATEWAY_HOST'/api/object_info?objectId={{object_id}}' | json_pp
```
Replace `{{object_id}}` in the command above with an
Expand All @@ -170,48 +105,75 @@ Replace `{{object_id}}` in the command above with an
actual object ID, for example one obtained from [`GET
/objects`](#get-objects) (without quotes).
### POST /transfer
Transfer an object from one address to another:
### POST /api/new_transfer
#### 1, Create a transaction to transfer an object from one address to another:
```shell
curl --location --request POST $SUI_GATEWAY_HOST/transfer \
curl --location --request POST $SUI_GATEWAY_HOST/api/new_transfer \
--header 'Content-Type: application/json' \
--data-raw '{
"fromAddress": "{{owner_address}}",
"objectId": "{{coin_object_id}}",
"toAddress": "{{to_address}}",
"gasObjectId": "{{gas_object_id}}"
"gasObjectId": "{{gas_object_id}}",
"gasBudget" : 10000
}' | json_pp
```
A transaction data response will be returned from the gateway server.
```json
{
"tx_bytes" : "VHJhbnNhY3Rpb25EYXRhOjoAACg4ZDZlMzM1ODIyYTA3MDk2MWUxZjU0ODk1OTEyZjViMzU0YjU1MzdkhPt2wu1YAh/975Vtmm/WOFKyUG0AAAAAAAAAACx6Z2ZaUmhSSXpZR2JhZEczdll1RjJJOE1QRFBQb0p1RWZFYmo0bm5XOWhZPSg4ZDZlMzM1ODIyYTA3MDk2MWUxZjU0ODk1OTEyZjViMzU0YjU1MzdkdcZgtOEVqjErVtDkaJihZzpGSfMAAAAAAAAAACwwWDRDamVzTFloZlhJVGhlWkhFYXN2bVFYWXJrOTJsdmhVa3hGN2NLaHZVPRAnAAAAAAAA"
}
```
#### 2, Sign the transaction using the Sui signtool
```shell
sui signtool --address <owner_address> --data <tx_bytes>
```
The signing tool will create and print out the signature and public key information.
You will see output resembling:
```shell
2022-04-04T21:42:44.915471Z INFO sui::sui_commands: Data to sign : VHJhbnNhY3Rpb25EYXRhOjoAACg4ZDZlMzM1ODIyYTA3MDk2MWUxZjU0ODk1OTEyZjViMzU0YjU1MzdkhPt2wu1YAh/975Vtmm/WOFKyUG0AAAAAAAAAACx6Z2ZaUmhSSXpZR2JhZEczdll1RjJJOE1QRFBQb0p1RWZFYmo0bm5XOWhZPSg4ZDZlMzM1ODIyYTA3MDk2MWUxZjU0ODk1OTEyZjViMzU0YjU1MzdkdcZgtOEVqjErVtDkaJihZzpGSfMAAAAAAAAAACwwWDRDamVzTFloZlhJVGhlWkhFYXN2bVFYWXJrOTJsdmhVa3hGN2NLaHZVPRAnAAAAAAAA
2022-04-04T21:42:44.915626Z INFO sui::sui_commands: Address : 8D6E335822A070961E1F54895912F5B354B5537D
2022-04-04T21:42:44.915915Z INFO sui::sui_commands: Public Key Base64: jAs+VmaKuEf4fpLNiLIHknEpft3zmy9b1v3AOYn/v4g=
2022-04-04T21:42:44.915919Z INFO sui::sui_commands: Signature : FULrl7iI1aQnb5OgCksYWJw6/Fv44wZZfeMXXN7CZJyooR2+Iu0WIVWUO61+r47aEidLeIewV8iLXFW7GPoYAw==
```
#### 3, Execute the transaction using the transaction data, signature and public key.
```shell
curl --location --request POST $SUI_GATEWAY_HOST/api/execute_transaction \
--header 'Content-Type: application/json' \
--data-raw '{
"tx_bytes": "{{tx_bytes}}",
"signature": "{{signature}}",
"pub_key": "{{public_key_base64}}"
}' | json_pp
```
Native transfer by `POST /transfer` is supported for coin
Native transfer by `POST /new_transfer` is supported for coin
objects only (including gas objects). Refer to
[transactions](transactions.md#native-transaction) documentation for
more information about a native transfer. Non-coin objects cannot be
transferred natively and require a [Move call](#post-call).
transferred natively and require a [Move call](#post-apimove_call).
You should replace `{{owner_address}}` and {{to_address}}' in the
You should replace `{{owner_address}}` and `{{to_address}}` in the
command above with an actual address values, for example one obtained
from [`GET /addresses`](#get-addresses). You should also replace
from `wallet.conf`. You should also replace
`{{coin_object_id}}` and `{{gas_object_id}}` in the command above with
an actual object ID, for example one obtained from [`GET
/objects`](#get-objects) (from `objType` in the output of [`GET
/objects`](#get-objects). You can see that all objects generated
/objects`](#get-apiobjects) (from `objectId` in the output of [`GET
/objects`](#get-apiobjects). You can see that all objects generated
during genesis are of `Coin/GAS` type). For this call to work, objects
represented by both `{{coin_object_id}}` and `{{gas_object_id}}` must
be owned by the address represented by `{{owner_address}}`.
#### POST /call
### POST /api/move_call
Execute a Move call transaction by calling the specified function in
#### 1, Execute a Move call transaction by calling the specified function in
the module of a given package (smart contracts in Sui are written in
the [Move](move.md#move) language):
```shell
curl --location --request POST $SUI_GATEWAY_HOST/call \
curl --location --request POST $SUI_GATEWAY_HOST/api/move_call \
--header 'Content-Type: application/json' \
--data-raw '{
"sender": "{{owner_address}}",
Expand All @@ -227,40 +189,45 @@ curl --location --request POST $SUI_GATEWAY_HOST/call \
}' | json_pp
```
#### 2, Sign the transaction
Follow the instructions to [sign the transaction](rest-api.md#2-sign-the-transaction-using-the-sui-signtool).
#### 3, Execute the transaction
Follow the instructions to [execute the transaction](rest-api.md#3-execute-the-transaction-using-the-transaction-data-signature-and-public-key).
Arguments are passed in, and type will be inferred from function
signature. Gas usage is capped by the gas_budget. The `transfer`
function is described in more detail in
the [Sui Wallet](wallet.md#calling-move-code) documentation.
Calling the `transfer` function in the `GAS` module serves the same
purpose as the native coin transfer ([`POST
/transfer`](#post-transfer)), and is mostly used for illustration
/api/transfer`](#post-apinew_transfer)), and is mostly used for illustration
purposes as native transfer is more efficient when it's applicable
(i.e., we are transferring coins rather than non-coin
objects). Consequently, you should fill out argument placeholders
(`{{owner_address}}`, `{{coin_object_id}`, etc.) the same way you
would for [`POST /transfer`](#post-transfer) - please not additional
would for [`POST /api/transfer`](#post-apinew_transfer) - please not additional
`0x` prepended to function arguments.
NOTE: A Publish endpoint is in the works, but for now the only way to add a new module is to have it included as part of genesis. To do this, add your Move module to `sui_programmability/framework/sources` before you hit the genesis endpoint. Once you have done this you will be able to use `"packageObjectId": "0x2"` in the call endpoint to find your Move module.
To learn more about what `args` are accepted in a Move call, refer to the [SuiJSON](sui-json.md) documentation.
#### POST /sync
### POST /api/sync_account_state
Synchronize client state with authorities:
```shell
curl --location --request POST $SUI_GATEWAY_HOST/sync \
curl --location --request POST $SUI_GATEWAY_HOST/api/sync_account_state \
--header 'Content-Type: application/json' \
--data-raw '{
"address": "{{address}}"
}' | json_pp
```
You should replace `{{address}}` in the command above with an actual
address value, for example one obtained from [`GET
/addresses`](#get-addresses) (without quotes).
address value, for example one obtained from `wallet.conf` (without quotes).
This will fetch the latest information on all objects owned by each
address that is managed by this server. This command has no output.
Expand Down
2 changes: 2 additions & 0 deletions sui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ serde_with = { version = "1.12.0", features = ["hex"] }
tracing = { version = "0.1.31", features = ["log"] }
tracing-subscriber = { version = "0.3.9", features = ["time", "registry", "env-filter"] }
serde-value = "0.7.0"
serde-name = "0.2.0"
log = "0.4.14"
dirs = "4.0.0"
telemetry_subscribers = { git = "https://github.com/MystenLabs/mysten-infra", rev = "a45af6dc28aa12c8cc13521d118c24aadd4c6adf" }
Expand Down Expand Up @@ -60,6 +61,7 @@ move-bytecode-utils = { git = "https://github.com/diem/move", rev = "2ef516919d5
move-unit-test = { git = "https://github.com/diem/move", rev = "2ef516919d5bbc728a57a2c0073b85c46d9fcf5a" }

once_cell = "1.9.0"
reqwest = { version = "0.11.10", features=["json","serde_json", "blocking"]}

[dev-dependencies]
tracing-test = "0.2.1"
Expand Down
17 changes: 9 additions & 8 deletions sui/src/gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ use sui_network::transport;
use sui_types::base_types::AuthorityName;
use sui_types::committee::Committee;

use crate::config::AuthorityInfo;
use crate::config::{AuthorityInfo, Config};
use crate::rest_gateway::RestGatewayClient;

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum GatewayType {
Embedded(EmbeddedGatewayConfig),
Embedded(GatewayConfig),
Rest(String),
}

Expand Down Expand Up @@ -66,23 +67,23 @@ impl GatewayType {
let authority_clients = config.make_authority_clients();
Box::new(GatewayState::new(path, committee, authority_clients))
}
_ => {
panic!("Unsupported gateway type")
}
GatewayType::Rest(url) => Box::new(RestGatewayClient { url: url.clone() }),
}
}
}

#[derive(Serialize, Deserialize)]
pub struct EmbeddedGatewayConfig {
pub struct GatewayConfig {
pub authorities: Vec<AuthorityInfo>,
pub send_timeout: Duration,
pub recv_timeout: Duration,
pub buffer_size: usize,
pub db_folder_path: PathBuf,
}

impl EmbeddedGatewayConfig {
impl Config for GatewayConfig {}

impl GatewayConfig {
pub fn make_committee(&self) -> Committee {
let voting_rights = self
.authorities
Expand All @@ -108,7 +109,7 @@ impl EmbeddedGatewayConfig {
}
}

impl Default for EmbeddedGatewayConfig {
impl Default for GatewayConfig {
fn default() -> Self {
Self {
authorities: vec![],
Expand Down
Loading

0 comments on commit 7c30c0a

Please sign in to comment.