diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8633882 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "geewallet"] + path = geewallet + url = https://github.com/aarani/geewallet.git diff --git a/Cargo.toml b/Cargo.toml index 852c7c2..f88acf7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ lightning-net-tokio = { version = "0.0.112" } tokio = { version = "1.14.1", features = ["full"] } tokio-postgres = { version="0.7.5" } futures = "0.3" +hex = "0.4.3" [profile.release] opt-level = 3 diff --git a/RgsToElectrumServerMiddleware/.gitignore b/RgsToElectrumServerMiddleware/.gitignore new file mode 100644 index 0000000..0626272 --- /dev/null +++ b/RgsToElectrumServerMiddleware/.gitignore @@ -0,0 +1,37 @@ +*.swp +*.*~ +project.lock.json +.DS_Store +*.pyc +nupkg/ + +# Visual Studio Code +.vscode + +# Rider +.idea + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +msbuild.log +msbuild.err +msbuild.wrn + +# Visual Studio 2015 +.vs/ \ No newline at end of file diff --git a/RgsToElectrumServerMiddleware/Program.fs b/RgsToElectrumServerMiddleware/Program.fs new file mode 100644 index 0000000..c1eae19 --- /dev/null +++ b/RgsToElectrumServerMiddleware/Program.fs @@ -0,0 +1,44 @@ +open System +open System.Threading.Tasks +open Microsoft.AspNetCore.Builder +open Microsoft.Extensions.Hosting + +open GWallet.Backend +open GWallet.Backend.UtxoCoin + +[] +let main args = + let builder = WebApplication.CreateBuilder args + let app = builder.Build() + + app.Urls.Add "http://0.0.0.0:5108" + + app.MapGet("/getTransaction/{height}/{txPos}", + Func>( + fun height txPos -> + task { + Console.WriteLine(sprintf "Request: looking for transaction #%s at block height #%s" txPos height) + + let height = Convert.ToUInt32 height + let txPos = Convert.ToUInt32 txPos + + let querySettings = + QuerySettings.Default ServerSelectionMode.Fast + + let getTransactionFromPosIdJob = ElectrumClient.GetBlockchainTransactionIdFromPos height txPos + let! txId = + Server.Query Currency.BTC querySettings getTransactionFromPosIdJob None + + let getTransactionJob = ElectrumClient.GetBlockchainTransaction txId + let! tx = + Server.Query Currency.BTC querySettings getTransactionJob None + + return tx + } + ) + ) |> ignore + + app.Run() + + 0 // Exit code + diff --git a/RgsToElectrumServerMiddleware/RgsToElectrumServerMiddleware.fsproj b/RgsToElectrumServerMiddleware/RgsToElectrumServerMiddleware.fsproj new file mode 100644 index 0000000..3ae80b2 --- /dev/null +++ b/RgsToElectrumServerMiddleware/RgsToElectrumServerMiddleware.fsproj @@ -0,0 +1,19 @@ + + + + net6.0 + + + + + + + + + + + + + + + diff --git a/RgsToElectrumServerMiddleware/appsettings.Development.json b/RgsToElectrumServerMiddleware/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/RgsToElectrumServerMiddleware/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/RgsToElectrumServerMiddleware/appsettings.json b/RgsToElectrumServerMiddleware/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/RgsToElectrumServerMiddleware/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/geewallet b/geewallet new file mode 160000 index 0000000..7626a16 --- /dev/null +++ b/geewallet @@ -0,0 +1 @@ +Subproject commit 7626a16ca28d05746a70d57bce829060baec1eed diff --git a/src/config.rs b/src/config.rs index 444d54c..e8bb5eb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -35,13 +35,13 @@ pub(crate) fn db_connection_config() -> Config { config } -pub(crate) fn bitcoin_rest_endpoint() -> HttpEndpoint { - let host = env::var("BITCOIN_REST_DOMAIN").unwrap_or("127.0.0.1".to_string()); - let port = env::var("BITCOIN_REST_PORT") - .unwrap_or("8332".to_string()) +pub(crate) fn middleware_rest_endpoint() -> HttpEndpoint { + let host = env::var("MIDDLEWARE_REST_DOMAIN").unwrap_or("127.0.0.1".to_string()); + let port = env::var("MIDDLEWARE_REST_PORT") + .unwrap_or("5108".to_string()) .parse::() - .expect("BITCOIN_REST_PORT env variable must be a u16."); - let path = env::var("BITCOIN_REST_PATH").unwrap_or("/rest/".to_string()); + .expect("MIDDLEWARE_REST_PORT env variable must be a u16."); + let path = env::var("MIDDLEWARE_REST_PATH").unwrap_or("/".to_string()); HttpEndpoint::for_host(host).with_port(port).with_path(path) } diff --git a/src/verifier.rs b/src/verifier.rs index 62c191a..d2a5880 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -1,11 +1,10 @@ +use hex; use std::convert::TryInto; -use bitcoin::{BlockHash, TxOut}; -use bitcoin::blockdata::block::Block; -use bitcoin::hashes::Hash; +use bitcoin::{BlockHash, TxOut, Transaction}; +use bitcoin::consensus::deserialize; use lightning::chain; use lightning::chain::AccessError; -use lightning_block_sync::{BlockData, BlockSource}; use lightning_block_sync::http::BinaryResponse; use lightning_block_sync::rest::RestClient; @@ -20,32 +19,42 @@ struct RestBinaryResponse(Vec); impl ChainVerifier { pub(crate) fn new() -> Self { ChainVerifier { - rest_client: RestClient::new(config::bitcoin_rest_endpoint()).unwrap(), + rest_client: RestClient::new(config::middleware_rest_endpoint()).unwrap(), } } - fn retrieve_block(&self, block_height: u32) -> Result { + fn retrieve_tx(&self, block_height: u32, transaction_index: u32) -> Result { tokio::task::block_in_place(move || { tokio::runtime::Handle::current().block_on(async move { - let uri = format!("blockhashbyheight/{}.bin", block_height); - let block_hash_result = + let uri = format!("getTransaction/{}/{}", block_height, transaction_index); + let tx_result = self.rest_client.request_resource::(&uri).await; - let block_hash: Vec = block_hash_result.map_err(|error| { - eprintln!("Could't find block hash at height {}: {}", block_height, error.to_string()); + let tx_hex_in_bytes: Vec = tx_result.map_err(|error| { + eprintln!("Could't find transaction at height {} and pos {}: {}", block_height, transaction_index, error.to_string()); AccessError::UnknownChain })?.0; - let block_hash = BlockHash::from_slice(&block_hash).unwrap(); - let block_result = self.rest_client.get_block(&block_hash).await; - match block_result { - Ok(BlockData::FullBlock(block)) => { - Ok(block) - }, - Ok(_) => unreachable!(), - Err(error) => { - eprintln!("Couldn't retrieve block {}: {:?} ({})", block_height, error, block_hash); - Err(AccessError::UnknownChain) - } - } + let tx_hex_in_string = + String::from_utf8(tx_hex_in_bytes) + .map_err(|non_utf8| String::from_utf8_lossy(non_utf8.as_bytes()).into_owned()) + .unwrap(); + + let tx_bytes = + hex::decode(tx_hex_in_string) + .map_err(|error| { + eprintln!("Could't find transaction at height {} and pos {}: {}", block_height, transaction_index, error.to_string()); + AccessError::UnknownChain + }) + .unwrap(); + + let transaction = + deserialize::(tx_bytes.as_slice()) + .map_err(|error| { + eprintln!("Could't find transaction at height {} and pos {}: {}", block_height, transaction_index, error.to_string()); + AccessError::UnknownChain + }) + .unwrap(); + + Ok(transaction) }) }) } } @@ -56,11 +65,8 @@ impl chain::Access for ChainVerifier { let transaction_index = ((short_channel_id >> 2 * 8) & 0xffffff) as u32; let output_index = (short_channel_id & 0xffff) as u16; - let block = self.retrieve_block(block_height)?; - let transaction = block.txdata.get(transaction_index as usize).ok_or_else(|| { - eprintln!("Transaction index {} out of bounds in block {} ({})", transaction_index, block_height, block.block_hash().to_string()); - AccessError::UnknownTx - })?; + let transaction = self.retrieve_tx(block_height, transaction_index)?; + let output = transaction.output.get(output_index as usize).ok_or_else(|| { eprintln!("Output index {} out of bounds in transaction {}", output_index, transaction.txid().to_string()); AccessError::UnknownTx