avail-light
Light client for the Avail blockchain


Introduction
avail-light is a data availability light client with the following functionalities:
- Listening on the Avail network for finalized blocks
- Random sampling and proof verification of a predetermined number of cells (
{row, col} pairs) on each new block. After successful block verification, confidence is calculated for a number of cells (N) in a matrix, with N depending on the percentage of certainty the light client wants to achieve.
- Data reconstruction through application client.
- HTTP endpoints exposing relevant data, both from the light and application clients
Modes of Operation
Once the data is received, light client verifies individual cells and calculates the confidence, which is then stored locally.
-
App-Specific Mode: If an App_ID > 0 is given in the config file, the application client (part of the light client) downloads all the relevant app data, reconstructs it and persists it locally. Reconstructed data is then available to accessed via an HTTP endpoint. (WIP)
-
Fat-Client Mode: The client retrieves larger contiguous chunks of the matrix on each block via RPC calls to an Avail node, and stores them on the DHT. This mode is activated when the block_matrix_partition parameter is set in the config file, and is mainly used with the disable_proof_verification flag because of the resource cost of cell validation.
IMPORTANT: disabling proof verification introduces a trust assumption towards the node, that the data provided is correct.
-
Crawl-Client Mode: Active if the crawl feature is enabled, and crawl_block parameter is set to true. The client crawls cells from DHT for entire block, and calculates success rate. Crawled cell proofs are not being verified, nor rows commitment equality check is being performed. Every block crawling is delayed by crawl_block_delay parameter. Delay should be enough so crawling of large block can be compensated. Success rate is emitted in logs and metrics. Crawler can be run in three modes: cells, rows and both. Default mode is cells, and it can be configured by crawl_block_mode parameter.
Installation
Download the Light Client from the releases page.
Light Client can also be built from the source:
git clone https://github.com/availproject/avail-light.git
cd avail-light
cargo build --release
Resulting avail-light binary can be found in the target/release directory.
Installation using Docker
Alternatively, you can use Docker to build and run the light client locally. Keep in mind that Docker image will
fail unless you have provided a config.yaml during the build process:
docker build -t avail-light .
It will cache the dependencies on the first build, after which you can run the image like:
docker run avail-light
Usage
Local development
For local development, a couple of prerequisites have to be met.
- Run the Avail node. For this setup, we'll run it in
dev mode:
./data-avail --dev --enable-kate-rpc
- A bootstrap node is required for deploying the Light Client(s) locally. Once the bootstrap has been downloaded and started, run the following command:
./avail-light --network local
Configuration file can also be used for the local deployment, as was the case for the testnet.
Example configuration file:
log_level = "info"
http_server_host = "127.0.0.1"
http_server_port = 7000
secret_key = { seed = "avail" }
port = 37000
full_node_ws = ["ws://127.0.0.1:9944"]
app_id = 0
confidence = 92.0
avail_path = "avail_path"
bootstraps = ["/ip4/127.0.0.1/tcp/39000/p2p/12D3KooWMm1c4pzeLPGkkCJMAgFbsfQ8xmVDusg272icWsaNHWzN"]
Full configuration reference can be found below.
NOTE
Flags and options take precedence to the configuration file if both are set (i.e. --port option overwrites the port parameter from the config file).
Example identity file:
WARNING: This file contains a private key. Please ensure only authorized access and prefer using encrypted storage.
avail_secret_seed_phrase = "bottom drive obey lake curtain smoke basket hold race lonely fit walk//Alice"
Options
--network <NETWORK>: Select a network for the Light Client to connect. Possible values are:
--config: Location of the configuration file
--identity: Location of the identity file
--app-id: The appID parameter for the application client
--port: LibP2P listener port
--verbosity: Log level. Possible values are:
trace
debug
info
warn
error
--avail-passphrase <PASSPHRASE>: Avail secret seed phrase password, flag is optional
--seed: Seed string for libp2p keypair generation
--secret-key: Ed25519 private key for libp2p keypair generation
Flags
--version: Light Client version
--clean: Remove previous state dir set in avail_path config parameter
--finality_sync_enable: Enable finality sync
Identity
In the Avail network, a light client's identity can be configured using the identity.toml file. If not specified, a secret seed phrase will be generated and stored in the identity file when the light client starts. To use an existing seed phrase, set the avail_secret_seed_phrase entry in the identity.toml file. Seed phrase will be used to derive Sr25519 key pair for signing. Location of the identity file can be specified using --identity option.
Configuration reference
log_level = "info"
http_server_host = "127.0.0.1"
http_server_port = 7000
secret_key = { seed={seed} }
port = 37000
autonat_only_global_ips = false
autonat_throttle = 2
autonat_retry_interval = 20
autonat_refresh_interval = 360
autonat_boot_delay = 10
bootstraps = ["/ip4/13.51.79.255/tcp/39000/p2p/12D3KooWE2xXc6C2JzeaCaEg7jvZLogWyjLsB5dA3iw5o3KcF9ds"]
relays = ["/ip4/13.49.44.246/tcp/39111/12D3KooWBETtE42fN7DZ5QsGgi7qfrN3jeYdXmBPL4peVTDmgG9b"]
full_node_ws = ["ws://127.0.0.1:9944"]
genesis_hash = "DEV123"
app_id = 0
confidence = 99.9
avail_path = "avail_path"
ot_collector_endpoint = "http://127.0.0.1:4317"
log_format_json = true
block_matrix_partition = "1/20"
disable_proof_verification = false
disable_rpc = false
query_proof_rpc_parallel_tasks = 8
max_cells_per_rpc = 30
dht_parallelization_limit = 20
block_processing_delay = 0
sync_start_block = 0
sync_finality_enable = false
record_ttl = 86400
publication_interval = 43200
replication_interval = 10800
replication_factor = 5
connection_idle_timeout = 30
query_timeout = 10
query_parallelism = 3
caching_max_peers = 1
disjoint_query_paths = false
max_kad_record_number = 2400000
max_kad_record_size = 8192
max_kad_provided_keys = 1024
Notes
- Immediately after starting a fresh light client, block sync is executed from a starting block set with the
sync_start_block config parameter. The sync process is using both the DHT and RPC for that purpose.
- In order to spin up a fat client, config needs to contain the
block_matrix_partition parameter set to a fraction of matrix. It is recommended to set the disable_proof_verification to true, because of the resource costs of proof verification.
sync_start_block needs to be set correspondingly to the blocks cached on the connected node (if downloading data via RPC).
- When an LC is freshly connected to a network, block finality is synced from the first block. If the LC is connected to a non-archive node on a long running network, initial validator sets won't be available and the finality checks will fail. In that case we recommend disabling the
sync_finality_enable flag
- When switching between the networks (i.e. local devnet), LC state in the
avail_path directory has to be cleared
- OpenTelemetry push metrics are used for light client observability
- In order to use network analyzer, the light client has to be compiled with
--features 'network-analysis' flag; when running the LC with network analyzer, sufficient capabilities have to be given to the client in order for it to have the permissions needed to listen on socket: sudo setcap cap_net_raw,cap_net_admin=eip /path/to/light/client/binary
Usage and examples
Fetching the number of the latest block processed by light client
To fetch the number of the latest block processed by light client, we can perform GET request on /v1/latest_block endpoint.
curl "http://localhost:7000/v1/latest_block"
Response:
{
"latest_block": 10
}
Fetching the confidence for given block
To fetch the confidence for specific block, which is already processed by application client, we can perform GET request on /v1/confidece/{block_number} endpoint.
curl "http://localhost:7000/v1/confidence/1"
Response:
{
"block": 1,
"confidence": 93.75,
"serialised_confidence": "5232467296"
}
serialisedConfidence is calculated as:
blockNumber << 32 | int32(confidence * 10 ** 7), where confidence is represented out of 10 ** 9.
Fetching decoded application data for given block
After data is verified, it can be fetched with GET request on /v1/appdata/{block_number} endpoint, by specifying decode=true query parameter. In case decode is omitted or false, scale encoded extrinsics will be returned.
JSON response
curl "http://localhost:7000/v1/appdata/1?decode=true"
Response:
{
"block": 46,
"extrinsics": [
"ZXhhbXBsZQ=="
]
}
Decoded extrinsic
curl -s "http://127.0.0.1:7000/v1/appdata/1?decode=true" | jq -r '.extrinsics[-1]' | base64 -d
Response:
"example"
Get the running mode of the Light Client
curl "localhost:7000/v1/mode"
Response:
{
"AppClient": 1
}
Get the status of a latest block
curl "localhost:7000/v1/status"
Response:
{
"block_num": 10,
"confidence": 93.75,
"app_id": 1
}
Get the latest block
curl "localhost:7000/v1/latest_block"
Response:
{
"latest_block": 255
}
Health check
To perform health check of the light client, run:
curl -I "localhost:7000/health"
200 OK is expected response.
API reference
In case of error, endpoints will return response with 500 Internal Server Error status code, and descriptive error message.
GET /v1/mode
Retrieves the operating mode of the light client. Light client can operate in two different modes, LightClient or AppClient, depending on configuration of application ID.
Responses
If operating mode is LightClient response is:
Status code: 200 OK
"LightClient"
In case of AppClient mode, response is:
Status code: 200 OK
{"AppClient": {app_id}}
GET /v1/latest_block
Retrieves the latest block processed by the light client.
Responses
Status code: 200 OK
{"latest_block":{block_number}}
GET /v1/confidence/{block_number}
Given a block number, it returns the confidence computed by the light client for that specific block.
Path parameters:
block_number - block number (required)
Responses
In case when confidence is computed:
Status code: 200 OK
{ "block": 1, "confidence": 93.75, "serialised_confidence": "5232467296" }
If confidence is not computed, and specified block is before the latest processed block:
Status code: 400 Bad Request
"Not synced"
If confidence is not computed, and specified block is after the latest processed block:
Status code: 404 Not Found
"Not found"
GET /v1/appdata/{block_number}
Given a block number, it retrieves the hex-encoded extrinsics for the specified block, if available. Alternatively, if specified by a query parameter, the retrieved extrinsic is decoded and returned as a base64-encoded string.
Path parameters:
block_number - block number (required)
Query parameters:
decode - true if decoded extrinsics are requested (boolean, optional, default is false)
Responses
If application data is available, and decode is false or unspecified:
Status code: 200 OK
{
"block": 1,
"extrinsics": [
"0xc5018400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01308e88ca257b65514b7b44fc1913a6a9af6abc34c3d22761b0e425674d68df7de26be1c8533a7bbd01fdb3a8daa5af77df6d3fb0a67cde8241f461f4fe16f188000000041d011c6578616d706c65"
]
}
If application data is available, and decode is true:
Status code: 200 OK
{ "block": 1, "extrinsics": ["ZXhhbXBsZQ=="] }
If application data is not available, and specified block is the latest block:
Status code: 401 Unauthorized
"Processing block"
If application data is not available, and specified block is not the latest block:
Status code: 404 Not Found
"Not found"
GET /v1/status
Retrieves the status of the latest block processed by the light client.
Path parameters:
block_number - block number (required)
Responses
If latest processed block exists, and app_id is configured (otherwise, app_id is not set):
Status code: 200 OK
{ "block_num": 89, "confidence": 93.75, "app_id": 1 }
If there are no processed blocks:
Status code: 404 Not Found
"Not found"
Test Code Coverage Report
We are using grcov to aggregate code coverage information and generate reports.
To install grcov, run:
cargo install grcov
Source code coverage data is generated when running tests with:
env RUSTFLAGS="-C instrument-coverage" \
LLVM_PROFILE_FILE="tests-coverage-%p-%m.profraw" \
cargo test
To generate the report, run:
grcov . -s . \
--binary-path ./target/debug/ \
-t html \
--branch \
--ignore-not-existing -o \
./target/debug/coverage/
To clean up generate coverage information files, run:
find . -name \*.profraw -type f -exec rm -f {} +
Open index.html from the ./target/debug/coverage/ folder to review coverage data.