forked from jl777/SuperNET
-
Notifications
You must be signed in to change notification settings - Fork 94
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* impl FeeEstimator, Logger, BroadcasterInterface * impl Filter for ElectrumClient * lightning conf + ChainMonitor for electrum * fix wasm build * impl keys_manager and channel_manager * NetGraphMsgHandler, PeerManager, spawn network * update best block for chainmon and channel manager * Mock LN events, Persist CM, Background Processing * 1st version of enable_lightning rpc for test * refactoring + Error handling * remove hardcoded lightning conf paramaters * move LN trait impls for Electrum to seperate file * enable_lightning test * move enable_lightning to dispacher_v2 * announce external ip address to LN * Add node color to configs and request
- Loading branch information
Showing
23 changed files
with
1,363 additions
and
199 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
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
Empty file.
Empty file.
Empty file.
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,100 @@ | ||
#[cfg(not(target_arch = "wasm32"))] | ||
use crate::utxo::rpc_clients::UtxoRpcClientEnum; | ||
#[cfg(not(target_arch = "wasm32"))] | ||
use common::ip_addr::myipaddr; | ||
use common::mm_ctx::MmArc; | ||
use common::mm_error::prelude::*; | ||
use ln_errors::{EnableLightningError, EnableLightningResult}; | ||
#[cfg(not(target_arch = "wasm32"))] | ||
use ln_utils::{network_from_string, start_lightning, LightningConf}; | ||
|
||
#[cfg(not(target_arch = "wasm32"))] | ||
use super::{lp_coinfind_or_err, MmCoinEnum}; | ||
|
||
mod ln_errors; | ||
mod ln_rpc; | ||
#[cfg(not(target_arch = "wasm32"))] mod ln_utils; | ||
|
||
#[derive(Deserialize)] | ||
pub struct EnableLightningRequest { | ||
pub coin: String, | ||
pub port: Option<u16>, | ||
pub name: String, | ||
pub color: Option<String>, | ||
} | ||
|
||
#[cfg(target_arch = "wasm32")] | ||
pub async fn enable_lightning(_ctx: MmArc, _req: EnableLightningRequest) -> EnableLightningResult<String> { | ||
MmError::err(EnableLightningError::UnsupportedMode( | ||
"'enable_lightning'".into(), | ||
"native".into(), | ||
)) | ||
} | ||
|
||
/// Start a BTC lightning node (LTC should be added later). | ||
#[cfg(not(target_arch = "wasm32"))] | ||
pub async fn enable_lightning(ctx: MmArc, req: EnableLightningRequest) -> EnableLightningResult<String> { | ||
// coin has to be enabled in electrum to start a lightning node | ||
let coin = lp_coinfind_or_err(&ctx, &req.coin).await?; | ||
|
||
let utxo_coin = match coin { | ||
MmCoinEnum::UtxoCoin(utxo) => utxo, | ||
_ => { | ||
return MmError::err(EnableLightningError::UnsupportedCoin( | ||
req.coin, | ||
"Only utxo coins are supported in lightning".into(), | ||
)) | ||
}, | ||
}; | ||
|
||
if !utxo_coin.as_ref().conf.lightning { | ||
return MmError::err(EnableLightningError::UnsupportedCoin( | ||
req.coin, | ||
"'lightning' field not found in coin config".into(), | ||
)); | ||
} | ||
|
||
let client = match &utxo_coin.as_ref().rpc_client { | ||
UtxoRpcClientEnum::Electrum(c) => c, | ||
UtxoRpcClientEnum::Native(_) => { | ||
return MmError::err(EnableLightningError::UnsupportedMode( | ||
"Lightning network".into(), | ||
"electrum".into(), | ||
)) | ||
}, | ||
}; | ||
|
||
let network = match &utxo_coin.as_ref().conf.network { | ||
Some(n) => network_from_string(n.clone())?, | ||
None => { | ||
return MmError::err(EnableLightningError::UnsupportedCoin( | ||
req.coin, | ||
"'network' field not found in coin config".into(), | ||
)) | ||
}, | ||
}; | ||
|
||
if req.name.len() > 32 { | ||
return MmError::err(EnableLightningError::InvalidRequest( | ||
"Node name length can't be more than 32 characters".into(), | ||
)); | ||
} | ||
let node_name = format!("{}{:width$}", req.name, " ", width = 32 - req.name.len()); | ||
|
||
let mut node_color = [0u8; 3]; | ||
hex::decode_to_slice( | ||
req.color.unwrap_or_else(|| "000000".into()), | ||
&mut node_color as &mut [u8], | ||
) | ||
.map_to_mm(|_| EnableLightningError::InvalidRequest("Invalid Hex Color".into()))?; | ||
|
||
let listen_addr = myipaddr(ctx.clone()) | ||
.await | ||
.map_to_mm(EnableLightningError::InvalidAddress)?; | ||
let port = req.port.unwrap_or(9735); | ||
|
||
let conf = LightningConf::new(client.clone(), network, listen_addr, port, node_name, node_color); | ||
start_lightning(&ctx, conf).await?; | ||
|
||
Ok("success".into()) | ||
} |
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,61 @@ | ||
use crate::CoinFindError; | ||
use common::mm_error::prelude::*; | ||
use common::HttpStatusCode; | ||
use derive_more::Display; | ||
use http::StatusCode; | ||
|
||
pub type EnableLightningResult<T> = Result<T, MmError<EnableLightningError>>; | ||
|
||
#[derive(Debug, Deserialize, Display, Serialize, SerializeErrorType)] | ||
#[serde(tag = "error_type", content = "error_data")] | ||
pub enum EnableLightningError { | ||
#[display(fmt = "Invalid request: {}", _0)] | ||
InvalidRequest(String), | ||
#[display(fmt = "Invalid address: {}", _0)] | ||
InvalidAddress(String), | ||
#[display(fmt = "Invalid path: {}", _0)] | ||
InvalidPath(String), | ||
#[display(fmt = "Lightning node already running")] | ||
AlreadyRunning, | ||
#[display(fmt = "{} is only supported in {} mode", _0, _1)] | ||
UnsupportedMode(String, String), | ||
#[display(fmt = "Lightning network is not supported for {}: {}", _0, _1)] | ||
UnsupportedCoin(String, String), | ||
#[display(fmt = "No such coin {}", _0)] | ||
NoSuchCoin(String), | ||
#[display(fmt = "System time error {}", _0)] | ||
SystemTimeError(String), | ||
#[display(fmt = "I/O error {}", _0)] | ||
IOError(String), | ||
#[display(fmt = "Hash error {}", _0)] | ||
HashError(String), | ||
#[display(fmt = "RPC error {}", _0)] | ||
RpcError(String), | ||
} | ||
|
||
impl HttpStatusCode for EnableLightningError { | ||
fn status_code(&self) -> StatusCode { | ||
match self { | ||
EnableLightningError::InvalidRequest(_) | ||
| EnableLightningError::RpcError(_) | ||
| EnableLightningError::UnsupportedCoin(_, _) => StatusCode::BAD_REQUEST, | ||
EnableLightningError::AlreadyRunning | EnableLightningError::UnsupportedMode(_, _) => { | ||
StatusCode::METHOD_NOT_ALLOWED | ||
}, | ||
EnableLightningError::InvalidAddress(_) | ||
| EnableLightningError::InvalidPath(_) | ||
| EnableLightningError::SystemTimeError(_) | ||
| EnableLightningError::IOError(_) | ||
| EnableLightningError::HashError(_) => StatusCode::INTERNAL_SERVER_ERROR, | ||
EnableLightningError::NoSuchCoin(_) => StatusCode::PRECONDITION_REQUIRED, | ||
} | ||
} | ||
} | ||
|
||
impl From<CoinFindError> for EnableLightningError { | ||
fn from(e: CoinFindError) -> Self { | ||
match e { | ||
CoinFindError::NoSuchCoin { coin } => EnableLightningError::NoSuchCoin(coin), | ||
} | ||
} | ||
} |
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 @@ | ||
use crate::utxo::rpc_clients::{electrum_script_hash, ElectrumClient, UtxoRpcClientOps, UtxoRpcError}; | ||
use bitcoin::blockdata::script::Script; | ||
use bitcoin::blockdata::transaction::Transaction; | ||
use bitcoin::consensus::encode; | ||
use bitcoin::hash_types::Txid; | ||
use common::block_on; | ||
use common::mm_error::prelude::MapToMmFutureExt; | ||
use futures::compat::Future01CompatExt; | ||
use lightning::chain::{chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}, | ||
Filter, WatchedOutput}; | ||
use rpc::v1::types::Bytes as BytesJson; | ||
|
||
impl FeeEstimator for ElectrumClient { | ||
// Gets estimated satoshis of fee required per 1000 Weight-Units. | ||
// TODO: use fn estimate_fee instead of fixed number when starting work on opening channels | ||
fn get_est_sat_per_1000_weight(&self, confirmation_target: ConfirmationTarget) -> u32 { | ||
match confirmation_target { | ||
// fetch background feerate | ||
ConfirmationTarget::Background => 253, | ||
// fetch normal feerate (~6 blocks) | ||
ConfirmationTarget::Normal => 2000, | ||
// fetch high priority feerate | ||
ConfirmationTarget::HighPriority => 5000, | ||
} | ||
} | ||
} | ||
|
||
impl BroadcasterInterface for ElectrumClient { | ||
fn broadcast_transaction(&self, tx: &Transaction) { | ||
let tx_bytes = BytesJson::from(encode::serialize_hex(tx).as_bytes()); | ||
let _ = Box::new( | ||
self.blockchain_transaction_broadcast(tx_bytes) | ||
.map_to_mm_fut(UtxoRpcError::from), | ||
); | ||
} | ||
} | ||
|
||
impl Filter for ElectrumClient { | ||
// Watches for this transaction on-chain | ||
fn register_tx(&self, _txid: &Txid, _script_pubkey: &Script) { unimplemented!() } | ||
|
||
// Watches for any transactions that spend this output on-chain | ||
fn register_output(&self, output: WatchedOutput) -> Option<(usize, Transaction)> { | ||
let selfi = self.clone(); | ||
let script_hash = hex::encode(electrum_script_hash(output.script_pubkey.as_ref())); | ||
let history = block_on(selfi.scripthash_get_history(&script_hash).compat()).unwrap_or_default(); | ||
|
||
if history.len() < 2 { | ||
return None; | ||
} | ||
|
||
for item in history.iter() { | ||
let transaction = match block_on(selfi.get_transaction_bytes(item.tx_hash.clone()).compat()) { | ||
Ok(tx) => tx, | ||
Err(_) => continue, | ||
}; | ||
|
||
let maybe_spend_tx: Transaction = match encode::deserialize(transaction.as_slice()) { | ||
Ok(tx) => tx, | ||
Err(_) => continue, | ||
}; | ||
|
||
for (index, input) in maybe_spend_tx.input.iter().enumerate() { | ||
if input.previous_output.txid == output.outpoint.txid | ||
&& input.previous_output.vout == output.outpoint.index as u32 | ||
{ | ||
return Some((index, maybe_spend_tx)); | ||
} | ||
} | ||
} | ||
None | ||
} | ||
} |
Oops, something went wrong.