Skip to content
Closed
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
23 changes: 19 additions & 4 deletions .github/workflows/vss-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ concurrency:
jobs:
build-and-test:
runs-on: ubuntu-latest
strategy:
matrix:
authorizer: [noop, sig, jwt]

services:
postgres:
Expand Down Expand Up @@ -39,10 +42,22 @@ jobs:
- name: Build and Deploy VSS Server
run: |
cd vss-server/rust
cargo run server/vss-server-config.toml&
- name: Run VSS Integration tests
if [ "${{ matrix.authorizer }}" == "noop" ]; then
RUSTFLAGS="--cfg noop_authorizer" cargo run --release --no-default-features server/vss-server-config.toml &
elif [ "${{ matrix.authorizer }}" == "jwt" ]; then
# Public key for testing purposes solely.
export VSS_JWT_RSA_PEM=$(cat ../../ldk-node/tests/fixtures/vss_jwt_rsa_pub.pem)
cargo run --release server/vss-server-config.toml &
elif [ "${{ matrix.authorizer }}" == "sig" ]; then
cargo run --release server/vss-server-config.toml &
else
echo "Unknown authorizer: ${{ matrix.authorizer }}" && exit 1
fi

- name: Run VSS Integration tests for ${{ matrix.authorizer }}
run: |
cd ldk-node
export TEST_VSS_BASE_URL="http://localhost:8080/vss"
RUSTFLAGS="--cfg vss_test" cargo test io::vss_store
RUSTFLAGS="--cfg vss_test --cfg cycle_tests" cargo test --test integration_tests_vss
RUSTFLAGS="--cfg vss_test --cfg ${{ matrix.authorizer }}_auth_test" cargo test --features test_utils io::vss_store
RUSTFLAGS="--cfg vss_test --cfg cycle_tests --cfg ${{ matrix.authorizer }}_auth_test" cargo test \
--features test_utils --test integration_tests_vss
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ panic = 'abort' # Abort on panic

[features]
default = []
test_utils = ["jsonwebtoken", "lightning/_test_utils"]

[dependencies]
#lightning = { version = "0.2.0", features = ["std"] }
Expand Down Expand Up @@ -79,6 +80,7 @@ vss-client = { package = "vss-client-ng", version = "0.4" }
prost = { version = "0.11.6", default-features = false}
#bitcoin-payment-instructions = { version = "0.6" }
bitcoin-payment-instructions = { git = "https://github.com/tnull/bitcoin-payment-instructions", rev = "e4d519b95b26916dc6efa22f8f1cc11a818ce7a7" }
jsonwebtoken = { version = "9.3.0", optional = true, default-features = false, features = ["use_pem"] }

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winbase"] }
Expand Down Expand Up @@ -123,6 +125,9 @@ check-cfg = [
"cfg(cln_test)",
"cfg(lnd_test)",
"cfg(cycle_tests)",
"cfg(noop_auth_test)",
"cfg(jwt_auth_test)",
"cfg(sig_auth_test)",
]

[[bench]]
Expand Down
6 changes: 5 additions & 1 deletion src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
//! Objects and traits for data persistence.

pub mod sqlite_store;
#[cfg(test)]
#[cfg(any(test, feature = "test_utils"))]
pub(crate) mod test_utils;

#[cfg(feature = "test_utils")]
pub use test_utils::get_fixed_headers;

pub(crate) mod utils;
pub mod vss_store;

Expand Down
110 changes: 110 additions & 0 deletions src/io/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
// accordance with one or both of these licenses.

#![allow(dead_code)]

use std::collections::{hash_map, HashMap};
use std::future::Future;
use std::panic::RefUnwindSafe;
Expand Down Expand Up @@ -350,3 +352,111 @@ pub(crate) fn do_test_store<K: KVStoreSync + Sync>(store_0: &K, store_1: &K) {
// Make sure everything is persisted as expected after close.
check_persisted_data!(persister_0_max_pending_updates * 2 * EXPECTED_UPDATES_PER_PAYMENT + 1);
}

#[cfg(all(feature = "test_utils", jwt_auth_test))]
mod jwt_auth {
use super::*;

use std::time::SystemTime;

use jsonwebtoken::{encode, Algorithm, EncodingKey, Header};
use serde::{Deserialize, Serialize};

// Private key for testing purposes solely.
const VSS_PRIVATE_PEM: &str = include_str!("../../tests/fixtures/vss_jwt_rsa_prv.pem");

#[derive(Serialize, Deserialize)]
struct TestClaims {
sub: String,
iat: i64,
nbf: i64,
exp: i64,
}

pub fn generate_test_jwt(private_pem: &str, user_id: &str) -> String {
let now =
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() as i64;

let claims =
TestClaims { sub: user_id.to_owned(), iat: now, nbf: now, exp: now + (60 * 10) };

let encoding_key = EncodingKey::from_rsa_pem(private_pem.as_bytes())
.expect("Failed to create EncodingKey");

encode(&Header::new(Algorithm::RS256), &claims, &encoding_key).unwrap()
}

pub fn get_fixed_headers() -> HashMap<String, String> {
let token = generate_test_jwt(VSS_PRIVATE_PEM, "test");
let mut headers = HashMap::new();
headers.insert("Authorization".to_string(), format!("Bearer {}", token));
return headers;
}
}

#[cfg(all(feature = "test_utils", sig_auth_test))]
mod sig_auth {
use super::*;

use std::time::SystemTime;
use std::time::UNIX_EPOCH;

use bitcoin::hashes::sha256::Hash;
use bitcoin::hashes::Hash as _;
use bitcoin::secp256k1::{self, SecretKey};

use crate::hex_utils;

// Must match vss-server's SignatureAuthorizer constant.
// See: https://github.com/lightningdevkit/vss-server/blob/main/rust/auth-impls/src/signature.rs#L21
const SIGNING_CONSTANT: &'static [u8] =
b"VSS Signature Authorizer Signing Salt Constant..................";

fn build_auth_token(secret_key: &SecretKey) -> String {
let secp = secp256k1::Secp256k1::new();
let pubkey = secret_key.public_key(&secp);
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();

let mut bytes_to_sign = Vec::new();
bytes_to_sign.extend_from_slice(SIGNING_CONSTANT);
bytes_to_sign.extend_from_slice(&pubkey.serialize());
bytes_to_sign.extend_from_slice(format!("{now}").as_bytes());

let hash = Hash::hash(&bytes_to_sign);
let msg = secp256k1::Message::from_digest(hash.to_byte_array());
let sig = secp.sign_ecdsa(&msg, &secret_key);

format!("{pubkey:x}{}{now}", hex_utils::to_string(&sig.serialize_compact()))
}

pub fn get_fixed_headers() -> HashMap<String, String> {
let secret_key = SecretKey::from_slice(&[42; 32]).unwrap();
let token = build_auth_token(&secret_key);
let mut headers = HashMap::new();
headers.insert("Authorization".to_string(), token);
return headers;
}
}

/// Returns a hashmap of fixed headers, where, depending on configuration,
/// corresponds to valid headers for no-op, signature-based, or jwt-based
/// authorizers on vss-server.
pub fn get_fixed_headers() -> HashMap<String, String> {
#[cfg(noop_auth_test)]
{
HashMap::new()
}

#[cfg(all(jwt_auth_test, feature = "test_utils"))]
{
jwt_auth::get_fixed_headers()
}

#[cfg(all(feature = "test_utils", sig_auth_test))]
{
sig_auth::get_fixed_headers()
}

#[cfg(not(any(noop_auth_test, all(jwt_auth_test, feature = "test_utils"), sig_auth_test)))]
HashMap::new()
}
26 changes: 17 additions & 9 deletions src/io/vss_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -962,14 +962,12 @@ impl VssStoreBuilder {
#[cfg(test)]
#[cfg(vss_test)]
mod tests {
use std::collections::HashMap;

use rand::distr::Alphanumeric;
use rand::{rng, Rng, RngCore};
use vss_client::headers::FixedHeaders;

use super::*;
use crate::io::test_utils::do_read_write_remove_list_persist;
use crate::io::test_utils::{do_read_write_remove_list_persist, get_fixed_headers};

#[test]
fn vss_read_write_remove_list_persist() {
Expand All @@ -978,9 +976,14 @@ mod tests {
let rand_store_id: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
let mut vss_seed = [0u8; 32];
rng.fill_bytes(&mut vss_seed);
let header_provider = Arc::new(FixedHeaders::new(HashMap::new()));
let vss_store =
VssStore::new(vss_base_url, rand_store_id, vss_seed, header_provider).unwrap();
let header_provider = get_fixed_headers();
let vss_store = VssStore::new(
vss_base_url,
rand_store_id,
vss_seed,
Arc::new(FixedHeaders::new(header_provider)),
)
.unwrap();
do_read_write_remove_list_persist(&vss_store);
}

Expand All @@ -991,9 +994,14 @@ mod tests {
let rand_store_id: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
let mut vss_seed = [0u8; 32];
rng.fill_bytes(&mut vss_seed);
let header_provider = Arc::new(FixedHeaders::new(HashMap::new()));
let vss_store =
VssStore::new(vss_base_url, rand_store_id, vss_seed, header_provider).unwrap();
let header_provider = get_fixed_headers();
let vss_store = VssStore::new(
vss_base_url,
rand_store_id,
vss_seed,
Arc::new(FixedHeaders::new(header_provider)),
)
.unwrap();

do_read_write_remove_list_persist(&vss_store);
drop(vss_store)
Expand Down
28 changes: 28 additions & 0 deletions tests/fixtures/vss_jwt_rsa_prv.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCuIYJJ1dzNmuct
fzj+W4EeJXic/A6gkHJOS7MHqAqOqMg49aZfOj6y4kmhU3/fal5OccJ4299ohSnJ
rMKwWoL5YHYD1Y742Ez/trpjETTV6CwjhLovCVtWbZrjivUnYb1fEeGoQ8p+COOK
yMM3s/iQVlhzqo86kZ9fcaGFizrykcRimSDOuN3V/AWcB3fcKufLS76z6ysNTwiK
X/wnBUEtofALIV1i9rcyFpumRGi/9lo80eVcC1TErxA3C5IEwJQ18XCatM2Hf2xi
4D35JDK80/0MY3u7TJgYrFpaThuKd3lnSSPx51enJUEaNgXuUNvTdKkFEn1ASRi5
LNbNLKhXAgMBAAECggEATokCcDaqjXjNxzFYDTBL/cK8sWDlX/mF9FYj+tIJYOoy
063HSa/FU3zH5KD6TVN2ET8xjLzt+AAHJtRqQouwArVExNnuz8EOiU5qpf++qrM6
JRLZvhkkPsjUUMf9ZbOpa1VvRyq8CzgLGC8QDPF4q/ClmBVW3/2JucxQIyD2hywE
MDc8on3nEvCzMGSxUm2EIQn30iF8W2WZyNLk4RK+UUOUHGsFUN0PRfsHFQCAar0V
ZnSxlJgDKETXGjkX8G+H+EyPd+oFH3QtZFTzxk6ghLEZV1vetqMI9WEFnMLKfmFW
tBGYuGcq+72G5mlJqlnix69A93SJziymlS/QWgKrQQKBgQDki5E++NoUyslKMZca
yYWokqxs6T0y15Cig7lDuRfcfDNDjbf9AkRpUZ0O9VESWhCiRG0NKUbHVlAlAb1h
EbWPc2QCs+Tzt2uqeavohbVb9NMsEFSKgx8oUuIisAgUo9Xui+80A+7s54PoeqnT
ULE7KYCbs5oMJjGwpuiolYFYpwKBgQDDDIsEyxdloE6MxpwRshYKzOWR0ADeKuIf
kwEpF1ap5Ng0PdAvIfQS/aRpeb/Tx8Uv2+YMTwX2RyvgbMBFjJa3TEqagFcS4Chu
tabLuyjMq9LlUQdsh4xqfGFF3vaT9coDpbzNvHcmLkK6gnrbnG6mG06xFybqBQ8I
k8dPpnN40QKBgQDUBqc5RKUNpRQZQOhucYcOXQSaBchA4rvMCWhW6+C3LIJiqZeH
ohLVomGS/wO3gtbrs494JlMDm4++xV5sL4HBE8w0tbAyanf4L+jMTz9xkDBZMM09
s2e0gTBJ/gWBIH3YUPoZx4xhPGejxijHYpUJzfcCfBzuKIDw4ef2fr0BAQKBgEcB
X/KExKW4cCALhXFjtWaFJOWqJUa7scnwyDFfT6tVpeeOwSUHZUUslRfYvJ6qUPyV
PvAoLHF1g2GV9YDcJ1nfKiGIqyox9EYpVuk/3yBzRLk6gEtgJRv236qB+p3uknY1
dcAn5fA+Uwh2y6b7EcTimAkb9oym/swOkDZM0CihAoGBAJ9W91zU9H5rMBwiWMKP
ppReTRxxN8oJNk0Cirxr58YHQNXtGWkno316/SPJZzML29c8+QAoJ8uatwzaZzt9
S6Cq2bYEyO7LPqs3SLRrK802QGvV7Y4P2rX4pjYOMM9qddOnT+qkVyyqVguazfDJ
xrhmGsrdBu3nBkwwpCBps6KZ
-----END PRIVATE KEY-----
9 changes: 9 additions & 0 deletions tests/fixtures/vss_jwt_rsa_pub.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAriGCSdXczZrnLX84/luB
HiV4nPwOoJByTkuzB6gKjqjIOPWmXzo+suJJoVN/32peTnHCeNvfaIUpyazCsFqC
+WB2A9WO+NhM/7a6YxE01egsI4S6LwlbVm2a44r1J2G9XxHhqEPKfgjjisjDN7P4
kFZYc6qPOpGfX3GhhYs68pHEYpkgzrjd1fwFnAd33Crny0u+s+srDU8Iil/8JwVB
LaHwCyFdYva3MhabpkRov/ZaPNHlXAtUxK8QNwuSBMCUNfFwmrTNh39sYuA9+SQy
vNP9DGN7u0yYGKxaWk4bind5Z0kj8edXpyVBGjYF7lDb03SpBRJ9QEkYuSzWzSyo
VwIDAQAB
-----END PUBLIC KEY-----
19 changes: 10 additions & 9 deletions tests/integration_tests_vss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
// accordance with one or both of these licenses.

#![cfg(vss_test)]
#![cfg(all(vss_test, feature = "test_utils"))]

mod common;

use std::collections::HashMap;
use rand::{rng, Rng};

use ldk_node::entropy::NodeEntropy;
use ldk_node::io::get_fixed_headers;
use ldk_node::Builder;
use rand::{rng, Rng};

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn channel_full_cycle_with_vss_store() {
Expand All @@ -29,7 +29,7 @@ async fn channel_full_cycle_with_vss_store() {
config_a.node_entropy,
vss_base_url.clone(),
"node_1_store".to_string(),
HashMap::new(),
get_fixed_headers(),
)
.unwrap();
node_a.start().unwrap();
Expand All @@ -43,7 +43,7 @@ async fn channel_full_cycle_with_vss_store() {
config_b.node_entropy,
vss_base_url,
"node_2_store".to_string(),
HashMap::new(),
get_fixed_headers(),
)
.unwrap();
node_b.start().unwrap();
Expand Down Expand Up @@ -84,7 +84,7 @@ async fn vss_v0_schema_backwards_compatibility() {
.build_with_vss_store_and_fixed_headers(
vss_base_url.clone(),
store_id.clone(),
HashMap::new(),
get_fixed_headers(),
)
.unwrap();

Expand Down Expand Up @@ -123,7 +123,7 @@ async fn vss_v0_schema_backwards_compatibility() {
node_entropy,
vss_base_url,
store_id,
HashMap::new(),
get_fixed_headers(),
)
.unwrap();

Expand Down Expand Up @@ -158,12 +158,13 @@ async fn vss_node_restart() {
builder.set_network(bitcoin::Network::Regtest);
builder.set_storage_dir_path(storage_path.clone());
builder.set_chain_source_esplora(esplora_url.clone(), None);

let node = builder
.build_with_vss_store_and_fixed_headers(
node_entropy,
vss_base_url.clone(),
store_id.clone(),
HashMap::new(),
get_fixed_headers(),
)
.unwrap();

Expand Down Expand Up @@ -197,7 +198,7 @@ async fn vss_node_restart() {
node_entropy,
vss_base_url,
store_id,
HashMap::new(),
get_fixed_headers(),
)
.unwrap();

Expand Down