Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 46 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,6 @@ jobs:
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --all-targets --all-features -- -D warnings

wasm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: extractions/setup-just@v2
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
targets: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
- name: Build crates for WASM
env:
CC: gcc
run: just build-wasm

unit-tests:
runs-on: ubuntu-latest
needs: [ clippy ]
Expand All @@ -92,3 +77,49 @@ jobs:
uses: ./.github/workflows/e2e-core.yml
with:
arkd-version: ${{ matrix.arkd-version }}

wasm_ubuntu:
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
arkd-version: [ 'v0.5.9' ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: extractions/setup-just@v2
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
targets: wasm32-unknown-unknown
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- uses: Swatinem/rust-cache@v2

- name: Build crates for WASM
run: just build-wasm

wasm_macos:
strategy:
fail-fast: false
matrix:
os: [ macos-latest ]
arkd-version: [ 'v0.5.9' ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: extractions/setup-just@v2
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
targets: wasm32-unknown-unknown
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

- name: Install LLVM and Clang
if: contains(matrix.os, 'macos')
run: brew install llvm
- uses: Swatinem/rust-cache@v2

- name: Build crates for WASM
run: PATH="/opt/homebrew/opt/llvm/bin:$PATH" cargo build -p ark-core -p ark-rest --target wasm32-unknown-unknown
7 changes: 6 additions & 1 deletion ark-rest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,9 @@ uuid = { version = "^1.8", default-features = false, features = ["serde", "v4",
getrandom = { version = "0.2", features = ["js"] }

[dev-dependencies]
tokio = { version = "1.41.0", features = ["macros", "rt"] }
js-sys = "0.3"
tokio = { version = "1.42", features = ["macros", "rt"] }
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
wasm-bindgen-test = "0.3"
web-sys = { version = "0.3.77", features = ["console"] }
12 changes: 5 additions & 7 deletions ark-rest/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,14 @@ impl Client {
}

pub async fn get_info(&self) -> Result<ark_core::server::Info, Error> {
let _info = ark_service_get_info(&self.configuration).await?;
let info = ark_service_get_info(&self.configuration).await?;

// TODO: Mapping from the `ark-rest` generated types to the `ark_core` types is too much of
// TODO: Mapping from the `ark-rest` generated types to the `ark_core` types is alot of
// a pain given that every field is currently optional. We are waiting for an update to the
// swagger file to continue.
// swagger file to make this nicer

//let info = info.try_into()?;
let info = info.try_into().map_err(|e| Error(Box::new(e)))?;

// Ok(info)

todo!()
Ok(info)
}
}
118 changes: 118 additions & 0 deletions ark-rest/src/models/v1_get_info_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,18 @@
*/

use crate::models;
use bitcoin::address::NetworkUnchecked;
use bitcoin::secp256k1;
use bitcoin::Address;
use bitcoin::Amount;
use bitcoin::Denomination;
use bitcoin::Network;
use bitcoin::PublicKey;
use serde::Deserialize;
use serde::Serialize;
use std::error::Error as StdError;
use std::fmt;
use std::str::FromStr;

#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct V1GetInfoResponse {
Expand Down Expand Up @@ -61,3 +71,111 @@ impl V1GetInfoResponse {
}
}
}

#[derive(Debug)]
pub enum ConversionError {
MissingPubkey,
MissingRoundLifetime,
MissingUnilateralExitDelay,
MissingRoundInterval,
MissingNetwork,
MissingDust,
MissingBoardingDescriptorTemplate,
MissingVtxoDescriptorTemplate,
MissingForfeitAddress,
InvalidNetwork,
ParseError(&'static str),
}

impl fmt::Display for ConversionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ConversionError::MissingPubkey => write!(f, "Missing pubkey field"),
ConversionError::MissingRoundLifetime => write!(f, "Missing round lifetime field"),
ConversionError::MissingUnilateralExitDelay => {
write!(f, "Missing unilateral exit delay field")
}
ConversionError::MissingRoundInterval => write!(f, "Missing round interval field"),
ConversionError::MissingNetwork => write!(f, "Missing network field"),
ConversionError::MissingDust => write!(f, "Missing dust field"),
ConversionError::MissingBoardingDescriptorTemplate => {
write!(f, "Missing boarding descriptor template field")
}
ConversionError::InvalidNetwork => write!(f, "Invalid network value"),
ConversionError::ParseError(msg) => write!(f, "Parse error: {}", msg),
ConversionError::MissingVtxoDescriptorTemplate => {
write!(f, "Missing vtxo descriptor template",)
}
ConversionError::MissingForfeitAddress => write!(f, "Missing forfeit address"),
}
}
}

impl StdError for ConversionError {}

impl TryFrom<V1GetInfoResponse> for ark_core::server::Info {
type Error = ConversionError;

fn try_from(value: V1GetInfoResponse) -> Result<Self, Self::Error> {
let pubkey = value.pubkey.ok_or(ConversionError::MissingPubkey)?;
let pubkey = secp256k1::PublicKey::from_str(pubkey.as_str())
.map_err(|_| ConversionError::ParseError("Failed parsing pubkey"))?;

let round_interval = value
.round_interval
.ok_or(ConversionError::MissingRoundInterval)?
.parse::<i64>()
.map_err(|_| ConversionError::ParseError("Failed to parse round_interval"))?;

let network = value.network.ok_or(ConversionError::MissingNetwork)?;
let network =
Network::from_str(network.as_str()).map_err(|_| ConversionError::InvalidNetwork)?;

let dust = value.dust.ok_or(ConversionError::MissingDust)?;
let dust = Amount::from_str_in(dust.as_str(), Denomination::Satoshi)
.map_err(|_| ConversionError::ParseError("Failed to parse dust"))?;

let unilateral_exit_delay = value
.unilateral_exit_delay
.ok_or(ConversionError::MissingUnilateralExitDelay)?
.parse()
.map_err(|_| ConversionError::ParseError("Failed to parse unilateral_exit_delay"))?;

let vtxo_tree_expiry = value
.round_lifetime
// TODO: our ark server doesn't return this value. I'm not sure it is mandatory?
.unwrap_or("30".to_string());

let vtxo_tree_expiry_seconds = u32::from_str(vtxo_tree_expiry.as_str()).map_err(|_| {
ConversionError::ParseError("Failed to parse round_lifetime to seconds")
})?;
let vtxo_tree_expiry = bitcoin::Sequence::from_seconds_ceil(vtxo_tree_expiry_seconds)
.map_err(|_| ConversionError::ParseError("Failed to parse round_lifetime"))?;

let forfeit_address = value
.forfeit_address
.ok_or(ConversionError::MissingForfeitAddress)?;
let forfeit_address: Address<NetworkUnchecked> = forfeit_address
.parse()
.map_err(|_| ConversionError::ParseError("Failed parsing forfeit address"))?;

let vtxo_descriptor_templates = value
.vtxo_descriptor_templates
.ok_or(ConversionError::MissingVtxoDescriptorTemplate)?;
let boarding_descriptor_template = value
.boarding_descriptor_template
.ok_or(ConversionError::MissingBoardingDescriptorTemplate)?;

Ok(ark_core::server::Info {
pk: pubkey,
vtxo_tree_expiry,
unilateral_exit_delay,
round_interval,
network,
dust,
boarding_descriptor_template,
vtxo_descriptor_templates,
forfeit_address: forfeit_address.assume_checked(),
})
}
}
22 changes: 22 additions & 0 deletions ark-rest/tests/wasm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#[ignore] // we want to run this test only manually as it needs a full ark server
#[wasm_bindgen_test::wasm_bindgen_test]
#[cfg_attr(not(target_arch = "wasm32"), allow(dead_code))]
async fn test_get_info() {
use ark_rest::Client;

let server_url = "http://localhost:7070".to_string();

let client = Client::new(server_url);

match client.get_info().await {
Ok(info) => {
assert!(info.round_interval > 0, "Round interval should be positive");

web_sys::console::log_1(&format!("Got info: {:?}", info).into());
}
Err(err) => {
web_sys::console::error_1(&format!("Error getting info: {:?}", err).into());
panic!("get_info failed with error: {:?}", err);
}
}
}
Loading