-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(offchain): adds the authority-claimer
- Loading branch information
Showing
16 changed files
with
630 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
[package] | ||
name = "authority-claimer" | ||
license = "Apache-2.0" | ||
version = "1.0.0" | ||
edition = "2021" | ||
|
||
[[bin]] | ||
name = "cartesi-rollups-authority-claimer" | ||
path = "src/main.rs" | ||
test = false | ||
|
||
[dependencies] | ||
http-server = { path = "../http-server" } | ||
rollups-events = { path = "../rollups-events" } | ||
|
||
thiserror = "1.0" | ||
|
||
async-trait.workspace = true | ||
clap = { workspace = true, features = ["derive"] } | ||
eth-tx-manager.workspace = true | ||
ethers.workspace = true | ||
rusoto_core.workspace = true | ||
serde.workspace = true | ||
serde_json.workspace = true | ||
snafu.workspace = true | ||
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } | ||
tracing-subscriber = { workspace = true, features = ["env-filter"] } | ||
tracing.workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// (c) Cartesi and individual authors (see AUTHORS) | ||
// SPDX-License-Identifier: Apache-2.0 (see LICENSE) | ||
|
||
use async_trait::async_trait; | ||
use tracing::{trace, warn}; | ||
|
||
use crate::{listener::BrokerListener, sender::ClaimSender}; | ||
|
||
/// The `AuthorityClaimer` starts an event loop that waits for claim messages | ||
/// from the broker, and then sends the claims to the blockchain. | ||
/// | ||
/// It uses a `BrokerListener` for listening for messages from the broker. | ||
/// | ||
/// It also uses a `ClaimSender` that interacts with the blockchain and | ||
/// effectively submits the claims. | ||
#[async_trait] | ||
pub trait AuthorityClaimer<'a, L: BrokerListener, S: ClaimSender> | ||
where | ||
L: 'a + Sync, | ||
S: 'a, | ||
{ | ||
async fn start( | ||
&'a self, | ||
broker_listener: L, | ||
claim_sender: S, | ||
) -> Result<(), AuthorityClaimerError<S, L>> { | ||
trace!("Starting the authority claimer loop"); | ||
let mut claim_sender = claim_sender; | ||
loop { | ||
match broker_listener.listen().await { | ||
Ok(rollups_claim) => { | ||
trace!("Got a claim from the broker: {:?}", rollups_claim); | ||
claim_sender = claim_sender | ||
.send_claim(rollups_claim) | ||
.await | ||
.map_err(AuthorityClaimerError::ClaimSenderError)?; | ||
} | ||
Err(e) => { | ||
warn!("Broker error `{}`", e); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, thiserror::Error)] | ||
pub enum AuthorityClaimerError<S: ClaimSender, L: BrokerListener> { | ||
#[error("claim sender error: {0}")] | ||
ClaimSenderError(S::Error), | ||
|
||
#[error("broker listener error: {0}")] | ||
BrokerListenerError(L::Error), | ||
} | ||
|
||
// ------------------------------------------------------------------------------------------------ | ||
// DefaultAuthorityClaimer | ||
// ------------------------------------------------------------------------------------------------ | ||
|
||
pub struct DefaultAuthorityClaimer; | ||
|
||
impl DefaultAuthorityClaimer { | ||
pub fn new() -> Self { | ||
Self | ||
} | ||
} | ||
|
||
impl<'a, L: BrokerListener, S: ClaimSender> AuthorityClaimer<'a, L, S> | ||
for DefaultAuthorityClaimer | ||
where | ||
L: 'a + Sync, | ||
S: 'a, | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
// (c) Cartesi and individual authors (see AUTHORS) | ||
// SPDX-License-Identifier: Apache-2.0 (see LICENSE) | ||
|
||
use clap::{command, Parser}; | ||
use eth_tx_manager::{ | ||
config::{TxEnvCLIConfig as TxManagerCLIConfig, TxManagerConfig}, | ||
Priority, | ||
}; | ||
use rollups_events::{BrokerCLIConfig, BrokerConfig}; | ||
use rusoto_core::Region; | ||
use snafu::ResultExt; | ||
use std::{fs, path::PathBuf, str::FromStr}; | ||
|
||
use crate::config::{ | ||
error::{ | ||
AuthConfigError, AuthSnafu, AuthorityClaimerConfigError, | ||
InvalidRegionSnafu, MnemonicFileSnafu, TxManagerSnafu, | ||
}, | ||
json::{read_json_file, DappDeployment}, | ||
AuthConfig, AuthorityClaimerConfig, | ||
}; | ||
|
||
// ------------------------------------------------------------------------------------------------ | ||
// AuthorityClaimerCLI | ||
// ------------------------------------------------------------------------------------------------ | ||
|
||
#[derive(Clone, Parser)] | ||
#[command(name = "rd_config")] | ||
#[command(about = "Configuration for rollups authority claimer")] | ||
pub(crate) struct AuthorityClaimerCLI { | ||
#[command(flatten)] | ||
txm_config: TxManagerCLIConfig, | ||
|
||
#[command(flatten)] | ||
auth_config: AuthCLIConfig, | ||
|
||
#[command(flatten)] | ||
broker_config: BrokerCLIConfig, | ||
|
||
/// Path to file with deployment json of dapp | ||
#[arg(long, env, default_value = "./dapp_deployment.json")] | ||
dapp_deployment_file: PathBuf, | ||
} | ||
|
||
impl TryFrom<AuthorityClaimerCLI> for AuthorityClaimerConfig { | ||
type Error = AuthorityClaimerConfigError; | ||
|
||
fn try_from(cli_config: AuthorityClaimerCLI) -> Result<Self, Self::Error> { | ||
let txm_config = TxManagerConfig::initialize(cli_config.txm_config) | ||
.context(TxManagerSnafu)?; | ||
|
||
let auth_config = | ||
AuthConfig::try_from(cli_config.auth_config).context(AuthSnafu)?; | ||
|
||
let broker_config = BrokerConfig::from(cli_config.broker_config); | ||
|
||
let dapp_deployment = | ||
read_json_file::<DappDeployment>(cli_config.dapp_deployment_file)?; | ||
let dapp_address = dapp_deployment.dapp_address; | ||
let dapp_deploy_block_hash = dapp_deployment.dapp_deploy_block_hash; | ||
|
||
Ok(AuthorityClaimerConfig { | ||
txm_config, | ||
auth_config, | ||
broker_config, | ||
dapp_address, | ||
dapp_deploy_block_hash, | ||
txm_priority: Priority::Normal, | ||
}) | ||
} | ||
} | ||
|
||
// ------------------------------------------------------------------------------------------------ | ||
// AuthConfig | ||
// ------------------------------------------------------------------------------------------------ | ||
|
||
#[derive(Debug, Clone, Parser)] | ||
#[command(name = "auth_config")] | ||
#[command(about = "Configuration for signing authentication")] | ||
pub(crate) struct AuthCLIConfig { | ||
/// Signer mnemonic, overrides `auth_mnemonic_file` and `auth_aws_kms_*` | ||
#[arg(long, env)] | ||
auth_mnemonic: Option<String>, | ||
|
||
/// Signer mnemonic file path, overrides `auth_aws_kms_*` | ||
#[arg(long, env)] | ||
auth_mnemonic_file: Option<String>, | ||
|
||
/// Mnemonic account index | ||
#[arg(long, env)] | ||
auth_mnemonic_account_index: Option<u32>, | ||
|
||
/// AWS KMS signer key-id | ||
#[arg(long, env)] | ||
auth_aws_kms_key_id: Option<String>, | ||
|
||
/// AWS KMS signer region | ||
#[arg(long, env)] | ||
auth_aws_kms_region: Option<String>, | ||
} | ||
|
||
impl TryFrom<AuthCLIConfig> for AuthConfig { | ||
type Error = AuthConfigError; | ||
|
||
fn try_from(cli: AuthCLIConfig) -> Result<Self, Self::Error> { | ||
let account_index = cli.auth_mnemonic_account_index; | ||
if let Some(mnemonic) = cli.auth_mnemonic { | ||
Ok(AuthConfig::Mnemonic { | ||
mnemonic, | ||
account_index, | ||
}) | ||
} else if let Some(path) = cli.auth_mnemonic_file { | ||
let mnemonic = fs::read_to_string(path.clone()) | ||
.context(MnemonicFileSnafu { path })? | ||
.trim() | ||
.to_string(); | ||
Ok(AuthConfig::Mnemonic { | ||
mnemonic, | ||
account_index, | ||
}) | ||
} else { | ||
match (cli.auth_aws_kms_key_id, cli.auth_aws_kms_region) { | ||
(None, _) => Err(AuthConfigError::MissingConfiguration), | ||
(Some(_), None) => Err(AuthConfigError::MissingRegion), | ||
(Some(key_id), Some(region)) => { | ||
let region = Region::from_str(®ion) | ||
.context(InvalidRegionSnafu)?; | ||
Ok(AuthConfig::Aws { key_id, region }) | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// (c) Cartesi and individual authors (see AUTHORS) | ||
// SPDX-License-Identifier: Apache-2.0 (see LICENSE) | ||
|
||
use eth_tx_manager::config::Error as TxManagerConfigError; | ||
use rusoto_core::region::ParseRegionError; | ||
use snafu::Snafu; | ||
use std::path::PathBuf; | ||
|
||
#[derive(Debug, Snafu)] | ||
#[snafu(visibility(pub(crate)))] | ||
pub enum AuthorityClaimerConfigError { | ||
#[snafu(display("TxManager configuration error: {}", source))] | ||
TxManagerError { source: TxManagerConfigError }, | ||
|
||
#[snafu(display("Auth configuration error: {}", source))] | ||
AuthError { source: AuthConfigError }, | ||
|
||
#[snafu(display("Read file error ({})", path.display()))] | ||
ReadFileError { | ||
path: PathBuf, | ||
source: std::io::Error, | ||
}, | ||
|
||
#[snafu(display("Json parse error ({})", path.display()))] | ||
JsonParseError { | ||
path: PathBuf, | ||
source: serde_json::Error, | ||
}, | ||
} | ||
|
||
#[derive(Debug, Snafu)] | ||
#[snafu(visibility(pub(crate)))] | ||
pub enum AuthConfigError { | ||
#[snafu(display("Missing auth configuration"))] | ||
MissingConfiguration, | ||
|
||
#[snafu(display( | ||
"Could not read mnemonic file at path `{}`: {}", | ||
path, | ||
source | ||
))] | ||
MnemonicFileError { | ||
path: String, | ||
source: std::io::Error, | ||
}, | ||
|
||
#[snafu(display("Missing AWS region"))] | ||
MissingRegion, | ||
|
||
#[snafu(display("Invalid AWS region"))] | ||
InvalidRegion { source: ParseRegionError }, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// (c) Cartesi and individual authors (see AUTHORS) | ||
// SPDX-License-Identifier: Apache-2.0 (see LICENSE) | ||
|
||
use ethers::types::{Address, H256}; | ||
use serde::{de::DeserializeOwned, Deserialize}; | ||
use snafu::ResultExt; | ||
use std::{fs::File, io::BufReader, path::PathBuf}; | ||
|
||
use crate::config::error::{ | ||
AuthorityClaimerConfigError, JsonParseSnafu, ReadFileSnafu, | ||
}; | ||
|
||
#[derive(Clone, Debug, Deserialize)] | ||
pub(crate) struct DappDeployment { | ||
#[serde(rename = "address")] | ||
pub dapp_address: Address, // TODO: can I use rollups_events types? | ||
|
||
#[serde(rename = "blockHash")] | ||
pub dapp_deploy_block_hash: H256, // TODO: can I use rollups_events types? | ||
} | ||
|
||
pub(crate) fn read_json_file<T: DeserializeOwned>( | ||
path: PathBuf, | ||
) -> Result<T, AuthorityClaimerConfigError> { | ||
let file = | ||
File::open(&path).context(ReadFileSnafu { path: path.clone() })?; | ||
let reader = BufReader::new(file); | ||
serde_json::from_reader(reader).context(JsonParseSnafu { path }) | ||
} |
Oops, something went wrong.