Skip to content

Commit

Permalink
Fix multi chain address, faucet support rooch address (#1712)
Browse files Browse the repository at this point in the history
* fix

* fix MultiChainAddress

* fmt

* fmt

* remove useless file & fix gas setting

* fix ci
  • Loading branch information
wow-sven committed May 21, 2024
1 parent 2beccc6 commit 31b2099
Show file tree
Hide file tree
Showing 23 changed files with 847 additions and 209 deletions.
336 changes: 279 additions & 57 deletions Cargo.lock

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ members = [
"crates/rooch-benchmarks",
"crates/rooch-test-transaction-builder",
"crates/data_verify",
"crates/rooch-faucet",
"frameworks/framework-builder",
"frameworks/framework-release",
"frameworks/moveos-stdlib",
Expand All @@ -53,6 +54,7 @@ default-members = [
"moveos/moveos",
"frameworks/framework-release",
"crates/rooch",
"crates/rooch-faucet"
]

# All workspace members should inherit these keys
Expand Down Expand Up @@ -110,6 +112,7 @@ rooch-store = { path = "crates/rooch-store" }
rooch-indexer = { path = "crates/rooch-indexer" }
rooch-da = { path = "crates/rooch-da" }
rooch-benchmarks = { path = "crates/rooch-benchmarks" }
rooch-faucet = { path = "crates/rooch-faucet" }
rooch-test-transaction-builder = { path = "crates/rooch-test-transaction-builder" }
data-verify = { path = "crates/data_verify" }

Expand Down Expand Up @@ -245,6 +248,28 @@ diesel = { version = "2.1.0", features = [
"serde_json",
"64-column-tables",
] }
axum = { version = "0.6.6", default-features = false, features = [
"headers",
"tokio",
"http1",
"http2",
"json",
"matched-path",
"original-uri",
"form",
"query",
"ws",
] }
axum-extra = "0.4.2"
axum-server = { version = "0.5.1", default-features = false, features = [
"tls-rustls",
] }
serenity = { version = "0.12.1", default-features = false, features = [
"client",
"gateway",
"rustls_backend",
"model",
] }
diesel-derive-enum = { version = "2.0.1", features = ["sqlite"] }
diesel_migrations = { version = "2.0.0" }
tap = "1.0.1"
Expand Down
30 changes: 22 additions & 8 deletions crates/rooch-faucet/src/discord.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use crate::App;
use crate::{App, FaucetRequest, FixedBTCAddressRequest, FixedRoochAddressRequest};
use clap::Parser;
use rooch_types::address::BitcoinAddress;
use rooch_types::address::{BitcoinAddress, RoochAddress};
use serenity::all::{CommandDataOption, CommandDataOptionValue, CommandOptionType};
use serenity::async_trait;
use serenity::builder::{CreateCommand, CreateCommandOption};
Expand All @@ -23,17 +23,27 @@ pub struct DiscordConfig {
impl App {
async fn handle_faucet_request(&self, options: &[CommandDataOption]) -> String {
let value = options
.get(0)
.first()
.expect("Expected address option")
.value
.clone();

match value {
CommandDataOptionValue::String(address) => {
let btc_address =
BitcoinAddress::from_str(address.as_str()).expect("Invalid address");
let request = match address.starts_with("0x") {
true => FaucetRequest::FixedRoochAddressRequest(FixedRoochAddressRequest {
recipient: RoochAddress::from_str(address.as_str())
.expect("Invalid address"),
}),
false => FaucetRequest::FixedBTCAddressRequest(FixedBTCAddressRequest {
recipient: BitcoinAddress::from_str(address.as_str())
.expect("Invalid address"),
}),
};

if let Err(err) = self.request(btc_address).await {
let address = request.recipient().to_string();

if let Err(err) = self.request(request).await {
tracing::error!("Failed make faucet request for {address:?}: {}", err);
format!("Internal Error: Failed to send funds to {address:?}")
} else {
Expand Down Expand Up @@ -70,8 +80,12 @@ impl EventHandler for App {
let command = CreateCommand::new("faucet")
.description("Request funds from the faucet")
.add_option(
CreateCommandOption::new(CommandOptionType::String, "address", "Your BTC address")
.required(true),
CreateCommandOption::new(
CommandOptionType::String,
"address",
"Your BTC/Rooch address",
)
.required(true),
);

let guild_command = Command::create_global_command(&ctx.http, command).await;
Expand Down
91 changes: 63 additions & 28 deletions crates/rooch-faucet/src/faucet.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
// Copyright (c) RoochNetwork
// SPDX-License-Identifier: Apache-2.0

use crate::metrics::FaucetMetrics;
use crate::FaucetError;
use crate::{metrics::FaucetMetrics, FaucetError, FaucetRequest};
use anyhow::Result;
use clap::Parser;
use move_core_types::language_storage::StructTag;
use moveos_types::transaction::MoveAction;
use prometheus::Registry;
use rooch_key::keystore::account_keystore::AccountKeystore;
use rooch_rpc_client::wallet_context::WalletContext;
use rooch_types::address::{BitcoinAddress, MultiChainAddress, RoochAddress};
use rooch_types::address::{MultiChainAddress, RoochAddress};
use rooch_types::authentication_key::AuthenticationKey;
use rooch_types::framework::transfer::TransferModule;
use std::env;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::{mpsc::Receiver, RwLock};
use tokio::sync::{mpsc::Receiver, RwLock, RwLockWriteGuard};

use rooch_rpc_api::jsonrpc_types::KeptVMStatusView;
use rooch_types::error::{RoochError, RoochResult};
use rooch_types::error::RoochError;

pub const DEFAULT_AMOUNT: u64 = 1_000_000_000;
pub const DEFAULT_AMOUNT: u64 = 1_000 * 8;

#[derive(Parser, Debug, Clone)]
pub struct FaucetConfig {
Expand Down Expand Up @@ -59,14 +59,17 @@ struct State {

pub struct Faucet {
state: Arc<RwLock<State>>,
faucet_receiver: Arc<RwLock<Receiver<BitcoinAddress>>>,
faucet_receiver: Arc<RwLock<Receiver<FaucetRequest>>>,
}

// TODO: add queue bitch run ?
// TODO: retry ?
// TODO: record faucet address
impl Faucet {
pub async fn new(
prometheus_registry: &Registry,
config: FaucetConfig,
faucet_receiver: Receiver<BitcoinAddress>,
faucet_receiver: Receiver<FaucetRequest>,
) -> Result<Self> {
let wallet = WalletContext::new(config.wallet_config_dir.clone()).unwrap();
let _metrics = FaucetMetrics::new(prometheus_registry);
Expand All @@ -91,9 +94,20 @@ impl Faucet {
}

async fn monitor_faucet_requests(&self) -> Result<(), FaucetError> {
while let Some(address) = self.faucet_receiver.write().await.recv().await {
if let Err(e) = self.transfer_gases(address).await {
tracing::error!("Transfer gases failed {}", e)
while let Some(request) = self.faucet_receiver.write().await.recv().await {
match request {
FaucetRequest::FixedBTCAddressRequest(req) => {
let mul_addr = MultiChainAddress::from(req.recipient);
if let Err(e) = self.transfer_gases_with_multi_addr(mul_addr).await {
tracing::error!("Transfer gases failed {}", e)
}
}
FaucetRequest::FixedRoochAddressRequest(req) => {
if let Err(e) = self.transfer_gases(req.recipient).await {
tracing::error!("Transfer gases failed {}", e)
}
}
_ => {}
}
}

Expand All @@ -106,27 +120,17 @@ impl Faucet {
// }
// }

// TODO: add queue bitch run ?
// TODO: retry ?
// TODO: record faucet address
async fn transfer_gases(&self, recipient: BitcoinAddress) -> Result<(), FaucetError> {
tracing::info!("transfer gases recipient: {}", recipient);

let state = self.state.write().await;

async fn execute_transaction<'a>(
&self,
action: MoveAction,
state: RwLockWriteGuard<'a, State>,
) -> Result<(), FaucetError> {
let sender: RoochAddress = state.context.client_config.active_address.unwrap();

let move_action = TransferModule::create_transfer_coin_to_multichain_address_action(
StructTag::from_str("0x3::gas_coin::GasCoin").unwrap(),
MultiChainAddress::from(recipient),
state.config.faucet_grant_amount.into(),
);

let pwd = state.wallet_pwd.clone();
let result = if let Some(session_key) = state.config.session_key.clone() {
let tx_data = state
.context
.build_tx_data(sender, move_action, None)
.build_tx_data(sender, action, None)
.await
.map_err(FaucetError::internal)?;
let tx = state
Expand All @@ -139,7 +143,7 @@ impl Faucet {
} else {
state
.context
.sign_and_execute(sender, move_action, pwd, None)
.sign_and_execute(sender, action, pwd, None)
.await
};

Expand All @@ -154,4 +158,35 @@ impl Faucet {
Err(e) => Err(FaucetError::transfer(e)),
}
}

async fn transfer_gases_with_multi_addr(
&self,
recipient: MultiChainAddress,
) -> Result<(), FaucetError> {
tracing::info!("transfer gases recipient: {}", recipient);

let state = self.state.write().await;

let move_action = TransferModule::create_transfer_coin_to_multichain_address_action(
StructTag::from_str("0x3::gas_coin::GasCoin").unwrap(),
recipient,
state.config.faucet_grant_amount.into(),
);

self.execute_transaction(move_action, state).await
}

async fn transfer_gases(&self, recipient: RoochAddress) -> Result<(), FaucetError> {
tracing::info!("transfer gases recipient: {}", recipient);

let state = self.state.write().await;

let move_action = TransferModule::create_transfer_coin_action(
StructTag::from_str("0x3::gas_coin::GasCoin").unwrap(),
recipient.into(),
state.config.faucet_grant_amount.into(),
);

self.execute_transaction(move_action, state).await
}
}
56 changes: 24 additions & 32 deletions crates/rooch-faucet/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0

use prometheus::{
register_histogram_with_registry, register_int_counter_with_registry,
register_int_gauge_with_registry, Histogram, IntCounter, IntGauge, Registry,
register_histogram_with_registry, register_int_counter_with_registry, Histogram, IntCounter,
Registry,
};

/// Prometheus metrics which can be displayed in Grafana, queried and alerted on
Expand All @@ -15,16 +15,15 @@ pub struct RequestMetrics {
pub(crate) total_requests_succeeded: IntCounter,
pub(crate) total_requests_shed: IntCounter,
pub(crate) total_requests_failed: IntCounter,
pub(crate) total_requests_disconnected: IntCounter,
pub(crate) process_latency: Histogram,
}

/// Metrics relevant to the running of the service
#[derive(Clone, Debug)]
pub struct FaucetMetrics {
pub(crate) current_executions_in_flight: IntGauge,
pub(crate) total_available_coins: IntGauge,
pub(crate) total_coin_requests_succeeded: IntGauge,
// pub(crate) current_executions_in_flight: IntGauge,
// pub(crate) total_available_coins: IntGauge,
// pub(crate) total_coin_requests_succeeded: IntGauge,
}

const LATENCY_SEC_BUCKETS: &[f64] = &[
Expand Down Expand Up @@ -58,13 +57,6 @@ impl RequestMetrics {
registry,
)
.unwrap(),
total_requests_disconnected: register_int_counter_with_registry!(
"total_requests_disconnected",
"Total number of requests where the client disconnected before the service \
returned a response",
registry,
)
.unwrap(),
process_latency: register_histogram_with_registry!(
"process_latency",
"Latency of processing a Faucet request",
Expand All @@ -77,26 +69,26 @@ impl RequestMetrics {
}

impl FaucetMetrics {
pub fn new(registry: &Registry) -> Self {
pub fn new(_: &Registry) -> Self {
Self {
current_executions_in_flight: register_int_gauge_with_registry!(
"current_executions_in_flight",
"Current number of transactions being executed in Faucet",
registry,
)
.unwrap(),
total_available_coins: register_int_gauge_with_registry!(
"total_available_coins",
"Total number of available coins in queue",
registry,
)
.unwrap(),
total_coin_requests_succeeded: register_int_gauge_with_registry!(
"total_coin_requests_succeeded",
"Total number of requests processed successfully in Faucet (both batch and non_batched)",
registry,
)
.unwrap(),
// current_executions_in_flight: register_int_gauge_with_registry!(
// "current_executions_in_flight",
// "Current number of transactions being executed in Faucet",
// registry,
// )
// .unwrap(),
// total_available_coins: register_int_gauge_with_registry!(
// "total_available_coins",
// "Total number of available coins in queue",
// registry,
// )
// .unwrap(),
// total_coin_requests_succeeded: register_int_gauge_with_registry!(
// "total_coin_requests_succeeded",
// "Total number of requests processed successfully in Faucet (both batch and non_batched)",
// registry,
// )
// .unwrap(),
}
}
}
Loading

0 comments on commit 31b2099

Please sign in to comment.