Commit Module
While a module can be written in any language, we currently provide some utilities for Rust, with the goal of supporting more generalized APIs and simplify development in languages other than Rust.
Commit-Boost is still in alpha development, all APIs are subject to change
In Rust, we provide utilities to load and run modules. Simply add to your Cargo.toml
:
commit-boost = { git = "https://github.com/Commit-Boost/commit-boost-client", rev = "..." }
You will now be able to import the utils with:
use commit_boost::prelude::*;
Config
Your module will likely need a configuration for the Node Operator to customize. This will have to be in the cb-config.toml
file, in the correct [[module]]
section. In the module, you can define and load your config as follows.
First, define all the parameters needed in a struct:
#[derive(Debug, Deserialize)]
struct ExtraConfig {
sleep_secs: u64,
}
then pass that struct to the load_commit_module_config
function, which will load and parse the config. Your custom config will be under the extra
field.
let config = load_commit_module_config::<ExtraConfig>().unwrap();
let to_sleep = config.extra.sleep_secs;
The loaded config
also has a few other useful fields:
- the unique
id
of the module - chain spec
- a
SignerClient
to call the SignerAPI, already setup with the correct JWT
Requesting signatures
At its core the Signer Module simply provides a signature on a 32-byte data digest. The signatures are currently provided with either the validator keys (BLS) or a proxy key (BLS or ECDSA) for a given validator key, both on the builder domain.
In the example we use TreeHash
, already used in the CL, to create the digest from a custom struct:
#[derive(TreeHash)]
struct Datagram {
data: u64,
}
Furthermore, in order to request a signature, we'd need a public key of the validator. You can get a list of available keys by calling:
let pubkeys = config.signer_client.get_pubkeys().await.unwrap();
Which will call the get_pubkeys
endpoint of the SignerAPI, returning all the consensus pubkeys and the corresponding proxy keys, of your module.
Then, we can request a signature either with a consensus key or with a proxy key:
With a consensus key
Requesting a signature is as simple as:
let datagram = Datagram { data: 1 };
let request = SignConsensusRequest::builder(pubkey).with_msg(&datagram);
let signature = config.signer_client.request_consensus_signature(&request).await.unwrap();
Where pubkey
is the validator (consensus) public key for which the signature is requested.
With a proxy key
You'll have to first request a proxy key be generated for a given consensus key. We support two signature schemes for proxies: BLS or ECDSA.
To request a proxy:
// BLS proxy
let proxy_delegation = self.config.signer_client.generate_proxy_key_bls(pubkey).await?;
let proxy_pubkey = proxy_delegation.message.proxy;
// or ECDSA proxy
let proxy_delegation = self.config.signer_client.generate_proxy_key_ecdsa(pubkey).await?;
let proxy_pubkey = proxy_delegation.message.proxy;
Where pubkey
is the validator (consensus) public key for which a proxy is to be generated.
Then you can use the generated proxy key to request a signature:
let datagram = Datagram { data: 1 };
let request = SignProxyRequest::builder(proxy_pubkey).with_msg(&datagram);
// if `proxy_pubkey` is a BLS proxy
let signature = config.signer_client.request_proxy_signature_bls(&request).await.unwrap();
// or for ECDSA proxy
let signature = config.signer_client.request_proxy_signature_ecdsa(&request).await.unwrap();
Metrics
We provide support for modules to record custom metrics which are automatically scraped by Prometheus. This involves three steps
Define metrics
You can use the prometheus
crate to create a custom registry and metrics, for example:
static ref MY_CUSTOM_REGISTRY: Registry = Registry::new_custom(Some("da_commit".to_string()), None).unwrap();
static ref SIG_RECEIVED_COUNTER: IntCounter = IntCounter::new("signature_received", "successful signature requests received").unwrap();
Start Metrics Provider
When starting the module, you should register all metrics, and start the MetricsProvider
:
MY_CUSTOM_REGISTRY.register(Box::new(SIG_RECEIVED_COUNTER.clone())).unwrap();
MetricsProvider::load_and_run(MY_CUSTOM_REGISTRY.clone());
The MetricsProvider
will load the configuration needed and start a server with a /metrics
endpoint for Prometheus to scrape.
Record metrics
All that is left is to use the metrics throughout your code:
SIG_RECEIVED_COUNTER.inc();
These will be automatically scraped by the Prometheus service running, and exposed on port 9090
. We plan to allow developers to ship pre-made dashboards together with their modules, to allow Node Operators to have an improved oversight on the modules they are running.