Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into feat/rocksdb
Browse files Browse the repository at this point in the history
  • Loading branch information
gregdhill committed May 11, 2022
2 parents 1412741 + b8f7d7f commit 42f57fe
Show file tree
Hide file tree
Showing 14 changed files with 252 additions and 114 deletions.
2 changes: 2 additions & 0 deletions bitcoin/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub enum Error {
TimeElapsed(#[from] Elapsed),
#[error("ElectrsError: {0}")]
ElectrsError(#[from] ElectrsError),
#[error("Connected to incompatable bitcoin core version: {0}")]
IncompatibleVersion(usize),

#[error("Could not confirm transaction")]
ConfirmationError,
Expand Down
29 changes: 26 additions & 3 deletions bitcoin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ extern crate num_derive;
/// Average time to mine a Bitcoin block.
pub const BLOCK_INTERVAL: Duration = Duration::from_secs(600); // 10 minutes
pub const DEFAULT_MAX_TX_COUNT: usize = 100_000_000;

/// the bitcoin core version.
/// See https://github.com/bitcoin/bitcoin/blob/833add0f48b0fad84d7b8cf9373a349e7aef20b4/src/rpc/net.cpp#L627
/// and https://github.com/bitcoin/bitcoin/blob/833add0f48b0fad84d7b8cf9373a349e7aef20b4/src/clientversion.h#L33-L37
pub const BITCOIN_CORE_VERSION_23: usize = 230_000;
const NOT_IN_MEMPOOL_ERROR_CODE: i32 = BitcoinRpcError::RpcInvalidAddressOrKey as i32;

// Time to sleep before retry on startup.
Expand Down Expand Up @@ -218,12 +221,26 @@ fn parse_bitcoin_network(src: &str) -> Result<Network, Error> {
}
}

struct ConnectionInfo {
chain: String,
version: usize,
}

fn get_info(rpc: &Client) -> Result<ConnectionInfo, Error> {
let blockchain_info = rpc.get_blockchain_info()?;
let network_info = rpc.get_network_info()?;
Ok(ConnectionInfo {
chain: blockchain_info.chain,
version: network_info.version,
})
}

/// Connect to a bitcoin-core full node or timeout.
async fn connect(rpc: &Client, connection_timeout: Duration) -> Result<Network, Error> {
info!("Connecting to bitcoin-core...");
timeout(connection_timeout, async move {
loop {
match rpc.get_blockchain_info().map_err(Into::<Error>::into) {
match get_info(rpc) {
Err(err)
if err.is_transport_error() =>
{
Expand All @@ -245,8 +262,14 @@ async fn connect(rpc: &Client, connection_timeout: Duration) -> Result<Network,
sleep(RETRY_DURATION).await;
continue;
}
Ok(GetBlockchainInfoResult { chain, .. }) => {
Ok(ConnectionInfo{chain, version}) => {
info!("Connected to {}", chain);
info!("Bitcoin version {}", version);

if version >= BITCOIN_CORE_VERSION_23 {
return Err(Error::IncompatibleVersion(version))
}

return parse_bitcoin_network(&chain);
}
Err(err) => return Err(err),
Expand Down
2 changes: 2 additions & 0 deletions runtime/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ pub enum Error {
InsufficientFunds,
#[error("Client does not support spec_version: expected {0}, got {1}")]
InvalidSpecVersion(u32, u32),
#[error("Client metadata is different from parachain metadata: expected {0}, got {1}")]
ParachainMetadataMismatch(String, String),
#[error("Failed to load credentials from file: {0}")]
KeyLoadingFailure(#[from] KeyLoadingError),
#[error("Error serializing: {0}")]
Expand Down
16 changes: 16 additions & 0 deletions runtime/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use codec::Encode;
use futures::{future::join_all, stream::StreamExt, FutureExt, SinkExt};
use module_oracle_rpc_runtime_api::BalanceWrapper;
use primitives::UnsignedFixedPoint;
use serde_json::{Map, Value};
use sp_runtime::FixedPointNumber;
use std::{collections::BTreeSet, future::Future, sync::Arc, time::Duration};
use subxt::{
Expand All @@ -30,15 +31,19 @@ const TRANSACTION_TIMEOUT: Duration = Duration::from_secs(300); // 5 minute time
cfg_if::cfg_if! {
if #[cfg(feature = "standalone-metadata")] {
const DEFAULT_SPEC_VERSION: u32 = 1;
const DEFAULT_SPEC_NAME: &str = "interbtc-standalone";
pub const SS58_PREFIX: u16 = 42;
} else if #[cfg(feature = "parachain-metadata-interlay")] {
const DEFAULT_SPEC_VERSION: u32 = 3;
const DEFAULT_SPEC_NAME: &str = "interlay-parachain";
pub const SS58_PREFIX: u16 = 2032;
} else if #[cfg(feature = "parachain-metadata-kintsugi")] {
const DEFAULT_SPEC_VERSION: u32 = 15;
const DEFAULT_SPEC_NAME: &str = "kintsugi-parachain";
pub const SS58_PREFIX: u16 = 2092;
} else if #[cfg(feature = "parachain-metadata-testnet")] {
const DEFAULT_SPEC_VERSION: u32 = 6;
const DEFAULT_SPEC_NAME: &str = "testnet-parachain";
pub const SS58_PREFIX: u16 = 42;
}
}
Expand Down Expand Up @@ -69,6 +74,17 @@ impl InterBtcParachain {
let api: RuntimeApi = ext_client.clone().to_runtime_api();

let runtime_version = ext_client.rpc().runtime_version(None).await?;
let default_spec_name = &Value::default();
let spec_name = runtime_version.other.get("specName").unwrap_or(default_spec_name);
if spec_name == DEFAULT_SPEC_NAME {
log::info!("spec_name={}", spec_name);
} else {
return Err(Error::ParachainMetadataMismatch(
DEFAULT_SPEC_NAME.into(),
spec_name.as_str().unwrap_or_default().into(),
));
}

if runtime_version.spec_version == DEFAULT_SPEC_VERSION {
log::info!("spec_version={}", runtime_version.spec_version);
log::info!("transaction_version={}", runtime_version.transaction_version);
Expand Down
14 changes: 10 additions & 4 deletions service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub trait Service<Config> {
async fn start(&self) -> Result<(), Error>;
}

pub struct ConnectionManager<Config: Clone, S: Service<Config>> {
pub struct ConnectionManager<Config: Clone, S: Service<Config>, F: Fn()> {
signer: InterBtcSigner,
wallet_name: Option<String>,
bitcoin_config: BitcoinConfig,
Expand All @@ -44,9 +44,10 @@ pub struct ConnectionManager<Config: Clone, S: Service<Config>> {
monitoring_config: MonitoringConfig,
config: Config,
_marker: PhantomData<S>,
increment_restart_counter: F,
}

impl<Config: Clone + Send + 'static, S: Service<Config>> ConnectionManager<Config, S> {
impl<Config: Clone + Send + 'static, S: Service<Config>, F: Fn()> ConnectionManager<Config, S, F> {
pub fn new(
signer: InterBtcSigner,
wallet_name: Option<String>,
Expand All @@ -55,6 +56,7 @@ impl<Config: Clone + Send + 'static, S: Service<Config>> ConnectionManager<Confi
service_config: ServiceConfig,
monitoring_config: MonitoringConfig,
config: Config,
increment_restart_counter: F,
) -> Self {
Self {
signer,
Expand All @@ -65,11 +67,12 @@ impl<Config: Clone + Send + 'static, S: Service<Config>> ConnectionManager<Confi
monitoring_config,
config,
_marker: PhantomData::default(),
increment_restart_counter,
}
}
}

impl<Config: Clone + Send + 'static, S: Service<Config>> ConnectionManager<Config, S> {
impl<Config: Clone + Send + 'static, S: Service<Config>, F: Fn()> ConnectionManager<Config, S, F> {
pub async fn start(&self) -> Result<(), Error> {
loop {
tracing::info!("Version: {}", S::VERSION);
Expand Down Expand Up @@ -132,7 +135,10 @@ impl<Config: Clone + Send + 'static, S: Service<Config>> ConnectionManager<Confi

match self.service_config.restart_policy {
RestartPolicy::Never => return Err(Error::ClientShutdown),
RestartPolicy::Always => continue,
RestartPolicy::Always => {
(self.increment_restart_counter)();
continue;
}
};
}
}
Expand Down
2 changes: 1 addition & 1 deletion vault/src/cancellation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ mod tests {
// check that if the selector fails, the error is propagated
let parachain_rpc = MockProvider::default();

let mut cancellation_scheduler = CancellationScheduler::new(parachain_rpc, 0, 0, AccountId::new([1u8; 32]));
let cancellation_scheduler = CancellationScheduler::new(parachain_rpc, 0, 0, AccountId::new([1u8; 32]));

// dropping the tx immediately - this effectively closes the channel
let (_, replace_event_rx) = mpsc::channel::<Event>(16);
Expand Down
4 changes: 2 additions & 2 deletions vault/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ use thiserror::Error;
pub enum Error {
#[error("Insufficient funds available")]
InsufficientFunds,
#[error("Value below dust amount")]
BelowDustAmount,
#[error("Failed to load or create bitcoin wallet: {0}")]
WalletInitializationFailure(BitcoinError),
#[error("Transaction contains more than one return-to-self uxto")]
Expand All @@ -27,6 +25,8 @@ pub enum Error {
DeadlineExpired,
#[error("Transaction not found")]
TransactionNotFound,
#[error("Faucet url not set")]
FaucetUrlNotSet,

#[error("ServiceError: {0}")]
ServiceError(#[from] ServiceError),
Expand Down
26 changes: 13 additions & 13 deletions vault/src/faucet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ use hex::FromHex;
use jsonrpc_core::Value;
use jsonrpc_core_client::{transports::http as jsonrpc_http, TypedClient};
use parity_scale_codec::{Decode, Encode};
use runtime::{
AccountId, BtcPublicKey, CurrencyId, CurrencyIdExt, InterBtcParachain, VaultId, VaultRegistryPallet, TX_FEES,
};
use runtime::{AccountId, CurrencyId, CurrencyIdExt, InterBtcParachain, VaultId, VaultRegistryPallet, TX_FEES};
use serde::{Deserialize, Deserializer};

#[derive(Debug, Clone, Deserialize)]
Expand Down Expand Up @@ -45,21 +43,26 @@ async fn get_funding(faucet_connection: TypedClient, vault_id: VaultId) -> Resul
Ok(())
}

pub async fn fund_and_register(
parachain_rpc: &InterBtcParachain,
faucet_url: &str,
vault_id: &VaultId,
maybe_public_key: Option<BtcPublicKey>,
) -> Result<(), Error> {
pub async fn fund_account(faucet_url: &str, vault_id: &VaultId) -> Result<TypedClient, Error> {
tracing::info!("Connecting to the faucet");
let connection = jsonrpc_http::connect::<TypedClient>(faucet_url).await?;
let currency_id: CurrencyId = vault_id.collateral_currency();

// Receive user allowance from faucet
if let Err(e) = get_funding(connection.clone(), vault_id.clone()).await {
tracing::warn!("Failed to get funding from faucet: {}", e);
}

Ok(connection)
}

pub async fn fund_and_register(
parachain_rpc: &InterBtcParachain,
faucet_url: &str,
vault_id: &VaultId,
) -> Result<(), Error> {
let connection = fund_account(faucet_url, vault_id).await?;
let currency_id: CurrencyId = vault_id.collateral_currency();

let user_allowance_in_dot: u128 = get_faucet_allowance(connection.clone(), "user_allowance").await?;
let registration_collateral = user_allowance_in_dot
.checked_mul(currency_id.inner().one())
Expand All @@ -68,9 +71,6 @@ pub async fn fund_and_register(
.ok_or(Error::ArithmeticUnderflow)?;

tracing::info!("Registering the vault");
if let Some(public_key) = maybe_public_key {
parachain_rpc.register_public_key(public_key).await?;
}
parachain_rpc.register_vault(vault_id, registration_collateral).await?;

// Receive vault allowance from faucet
Expand Down
10 changes: 7 additions & 3 deletions vault/src/issue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use bitcoin::{BitcoinCoreApi, BlockHash, Transaction, TransactionExt};
use futures::{channel::mpsc::Sender, future, SinkExt, StreamExt};
use runtime::{
BtcAddress, BtcPublicKey, BtcRelayPallet, CancelIssueEvent, ExecuteIssueEvent, H256Le, InterBtcParachain,
IssuePallet, PrettyPrint, RequestIssueEvent, UtilFuncs, H256,
IssuePallet, PrettyPrint, RequestIssueEvent, UtilFuncs, VaultId, H256,
};
use service::Error as ServiceError;
use sha2::{Digest, Sha256};
Expand Down Expand Up @@ -70,10 +70,14 @@ pub async fn process_issue_requests<B: BitcoinCoreApi + Clone + Send + Sync + 's
pub async fn add_keys_from_past_issue_request<B: BitcoinCoreApi + Clone + Send + Sync + 'static>(
bitcoin_core: &B,
btc_parachain: &InterBtcParachain,
vault_id: &VaultId,
) -> Result<(), Error> {
let issue_requests = btc_parachain
let issue_requests: Vec<_> = btc_parachain
.get_vault_issue_requests(btc_parachain.get_account_id().clone())
.await?;
.await?
.into_iter()
.filter(|(_, issue)| &issue.vault == vault_id)
.collect();

let btc_start_height = match issue_requests.iter().map(|(_, request)| request.btc_height).min() {
Some(x) => x as usize,
Expand Down
8 changes: 6 additions & 2 deletions vault/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use runtime::InterBtcSigner;
use service::{warp, warp::Filter, ConnectionManager, Error, MonitoringConfig, ServiceConfig};
use std::net::{Ipv4Addr, SocketAddr};

use vault::{metrics, VaultService, VaultServiceConfig, ABOUT, AUTHORS, NAME, VERSION};
use vault::{
metrics::{self, increment_restart_counter},
VaultService, VaultServiceConfig, ABOUT, AUTHORS, NAME, VERSION,
};

#[derive(Parser, Debug, Clone)]
#[clap(name = NAME, version = VERSION, author = AUTHORS, about = ABOUT)]
Expand Down Expand Up @@ -40,14 +43,15 @@ async fn start() -> Result<(), Error> {
let (pair, wallet_name) = opts.account_info.get_key_pair()?;
let signer = InterBtcSigner::new(pair);

let vault_connection_manager = ConnectionManager::<_, VaultService>::new(
let vault_connection_manager = ConnectionManager::<_, VaultService, _>::new(
signer.clone(),
Some(wallet_name.to_string()),
opts.bitcoin,
opts.parachain,
opts.service,
opts.monitoring.clone(),
opts.vault,
|| increment_restart_counter(),
);

if !opts.monitoring.no_prometheus {
Expand Down
17 changes: 16 additions & 1 deletion vault/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use futures::{try_join, StreamExt, TryFutureExt};
use lazy_static::lazy_static;
use runtime::{
prometheus::{
gather, proto::MetricFamily, Encoder, Gauge, GaugeVec, IntGauge, IntGaugeVec, Opts, Registry, TextEncoder,
gather, proto::MetricFamily, Encoder, Gauge, GaugeVec, IntCounter, IntGauge, IntGaugeVec, Opts, Registry,
TextEncoder,
},
CollateralBalancesPallet, CurrencyId, CurrencyIdExt, CurrencyInfo, Error, FeedValuesEvent, FixedU128,
InterBtcParachain, InterBtcRedeemRequest, IssuePallet, IssueRequestStatus, OracleKey, RedeemPallet,
Expand Down Expand Up @@ -94,6 +95,8 @@ lazy_static! {
pub static ref FEE_BUDGET_SURPLUS: GaugeVec =
GaugeVec::new(Opts::new("fee_budget_surplus", "Fee Budget Surplus"), &[CURRENCY_LABEL])
.expect("Failed to create prometheus metric");
pub static ref RESTART_COUNT: IntCounter =
IntCounter::new("restart_count", "Number of service restarts").expect("Failed to create prometheus metric");
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -298,6 +301,7 @@ pub fn register_custom_metrics() -> Result<(), Error> {
REGISTRY.register(Box::new(MEAN_POLL_DURATION.clone()))?;
REGISTRY.register(Box::new(MEAN_SCHEDULED_DURATION.clone()))?;
REGISTRY.register(Box::new(REMAINING_TIME_TO_REDEEM_HOURS.clone()))?;
REGISTRY.register(Box::new(RESTART_COUNT.clone()))?;

Ok(())
}
Expand Down Expand Up @@ -438,6 +442,10 @@ fn publish_utxo_count<B: BitcoinCoreApi + Clone + Send + Sync>(vault: &VaultData
}
}

pub fn increment_restart_counter() {
RESTART_COUNT.inc();
}

async fn publish_issue_count<
B: BitcoinCoreApi + Clone + Send + Sync + 'static,
V: VaultDataReader<B>,
Expand Down Expand Up @@ -1008,6 +1016,13 @@ mod tests {
assert_eq!(bitcoin_upper_bound, 13.0);
}

#[tokio::test]
async fn test_metrics_restart_counter() {
assert_eq!(RESTART_COUNT.get(), 0);
increment_restart_counter();
assert_eq!(RESTART_COUNT.get(), 1);
}

#[tokio::test]
async fn test_bitcoin_metrics() {
let mut btc_rpc = MockBitcoin::default();
Expand Down
Loading

0 comments on commit 42f57fe

Please sign in to comment.