Sui Gas Pool is a service that powers sponsored transactions on Sui at scale. It manages a database of gas coins owned by a sponsor address and provides APIs to reserve gas coins and use them to pay for transactions. It achieves scalability and high throughput by managing a large number of gas coin objects in the pool, so that it can sponsor a large number of transactions concurrently.
A typical flow that interacts with the gas pool service looks like the following:
A gas pool service instance corresponds to one sponsor address. A gas pool service instance will contain the following components:
The storage layer stores all the gas coins in the pool and reservation information. It is the only place where we persist data. It uses Redis store as the backend, and Lua scripts to control the logic. Detailed documentation of each Lua script can be found in link.
The Gas Pool Server contains a RPC server that accepts JSON-RPC requests, as well as an initializer that is able to initialize and fund gas coins to the pool:
The gas pool service starts a RPC Server that listens on a specified port. It supports permission control through barer secret token. An internal server that communicates with the gas pool service must specify the token in the request. This is also why an internal server is needed such that the barer token is not exposed to the public. An HTTP server is implemented to take the following 3 requests:
ReserveGasRequest
parameter in JSON form, and
returns ReserveGasResponse
.ExecuteTxRequest
parameter
in JSON form, and
returns ExecuteTxResponse
.pub struct ReserveGasRequest {
/// Desired gas budget. The response will contain gas coins that have total balance >= gas_budget.
pub gas_budget: u64,
/// The reserved gas coins will be released back to the pool after this duration expires.
pub reserve_duration_secs: u64,
}
pub struct ReserveGasResponse {
pub result: Option<ReserveGasResult>,
pub error: Option<String>,
}
pub struct ReserveGasResult {
pub sponsor_address: SuiAddress,
pub reservation_id: ReservationID,
pub gas_coins: Vec<SuiObjectRef>,
}
pub struct ExecuteTxRequest {
/// This must be the same reservation ID returned in ReserveGasResponse.
pub reservation_id: ReservationID,
/// BCS serialized transaction data bytes without its type tag, as base-64 encoded string.
pub tx_bytes: Base64,
/// User signature (`flag || signature || pubkey` bytes, as base-64 encoded string). Signature is committed to the intent message of the transaction data, as base-64 encoded string.
pub user_sig: Base64,
}
pub struct ExecuteTxResponse {
pub effects: Option<SuiTransactionBlockEffects>,
pub error: Option<String>,
}
The Gas Pool Initializer is able to initialize the global gas pool, as well as processing new funds and adding new coins to the gas pool. When we are starting up the gas pool for a given sponsor address for the first time, it will trigger the initialization process. It looks at all the SUI coins currently owned by the sponsor address, and split them into gas coins with a specified target balance. Once a day, it also looks at whether there is any coin owned by the sponsor address with a very large balance (NEW_COIN_BALANCE_FACTOR_THRESHOLD * target_init_balance), and if so it triggers initialization process again on the newly detected coin. This allows us add funding to the gas pool. To speed up the initialization time, it is able to split coins into smaller coins in parallel. Before each initialization run, it acquires a lock from the store to ensure that no other initialization task is running at the same time. The lock expires automatically after 12 hours. This allows us to run multiple gas servers for the same sponsor address.
The sponsor will need to sign transactions since it owns the gas coins. The gas pool supports two different signer implementations:
sui-gas-station
BinaryThe binary takes a an argument:
--config-path
(required): Path to the config file.tool
BinaryThe tool
binary currently supports a few helper commands:
benchmark
: This starts a stress benchmark that continuously send gas reservation request to the gas station server,
and measures number of requests processed per second. Each reservation expires automatically after 1 second so the
unused gas are put back to the pool.generate-sample-config
: This generates a sample config file that can be used to start the gas station server.cli
: Provides a few CLI commands to interact with the gas station server.Below describes the steps to deploy a gas pool service:
GAS_STATION_AUTH
environment
variable when starting the gas pool server.To create a YAML config file, you can use the following command to generate a sample config:
tool generate-sample-config --config-path sample.yaml --with-sidecar-signer
---
signer-config:
sidecar:
sidecar_url: "http://localhost:3000"
rpc-host-ip: 0.0.0.0
rpc-port: 9527
metrics-port: 9184
gas-pool-config:
redis:
redis_url: "redis://127.0.0.1"
fullnode-url: "http://localhost:9000"
coin-init-config:
target-init-balance: 100000000
refresh-interval-sec: 86400
daily-gas-usage-cap: 1500000000000
If you want to use in-memory signer, you can remove --with-sidecar-signer
from the command.
A description of these fields: