Skip to content

Commit

Permalink
Add integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Tibo-lg committed Aug 28, 2020
1 parent 7c40cd0 commit 8fda81b
Show file tree
Hide file tree
Showing 6 changed files with 311 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
services:
- docker
language: rust
rust:
- stable
env:
- BITCOINVERSION=0.20.0

script:
- cargo build --verbose
- cargo test --verbose
# Integration test
- ./scripts/start_node.sh
# Bitcoind takes forever to be ready on travis
- sleep 5
- (cd integration_test && cargo run)
- ./scripts/stop_node.sh

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

members = [
"dlc",
"integration_test",
]
12 changes: 12 additions & 0 deletions integration_test/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "integration_test"
version = "0.0.1"
authors = ["Crypto Garage"]

[dependencies]
bitcoin = {version="0.23.0-adaptor.0", git = "https://github.com/tibo-lg/rust-bitcoin", branch = "ecdsa-adaptor", package="bitcoin", features = ["bitcoinconsensus"]}
secp256k1 = {version="0.17.3-adaptor.0", git = "https://github.com/tibo-lg/rust-secp256k1", branch = "ecdsa-adaptor", package="secp256k1", features=["rand-std"]}
bitcoin_hashes = "0.7.6"
bitcoincore-rpc = {version="0.11.0-adaptor.0", git = "https://github.com/Tibo-lg/rust-bitcoincore-rpc", branch = "ecdsa-adaptor"}
bitcoincore-rpc-json = {version="0.11.0-adaptor.0", git = "https://github.com/Tibo-lg/rust-bitcoincore-rpc", branch = "ecdsa-adaptor"}
dlc = {path = "../dlc"}
272 changes: 272 additions & 0 deletions integration_test/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
extern crate bitcoin;
extern crate bitcoin_hashes;
extern crate bitcoincore_rpc;
extern crate bitcoincore_rpc_json;
extern crate dlc;
extern crate secp256k1;

use bitcoincore_rpc::{Auth, Client, RpcApi};
use bitcoincore_rpc_json::AddressType;

use bitcoin::network::constants::Network;
use bitcoin::{Address, OutPoint, PrivateKey, SigHashType};
use bitcoin_hashes::{sha256, Hash};
use dlc::{InputType, Outcome, PartyParams, TxInputInfo};
use secp256k1::Message;

const LOCALPARTY: &str = "alice";
const REMOTEPARTY: &str = "bob";
const SINK: &str = "sink";

const RPCBASE: &str = "http://localhost:18443";

const BTC_TO_SAT: u64 = 100000000;
const PARTY_COLLATERAL: u64 = 1 * BTC_TO_SAT;
const WIN: &str = "WIN";
const LOSE: &str = "LOSE";

fn outcomes() -> Vec<Outcome> {
vec![
Outcome {
local: 2 * BTC_TO_SAT,
remote: 0,
},
Outcome {
local: 0,
remote: 2 * BTC_TO_SAT,
},
]
}

fn hashed_msg() -> Vec<Message> {
[WIN, LOSE]
.iter()
.map(|m| {
Message::from_slice(sha256::Hash::hash(&m.as_bytes()).into_inner()[..].as_ref())
.unwrap()
})
.collect()
}

fn get_new_wallet_rpc(default_rpc: &Client, wallet_name: &str, auth: Auth) -> Client {
default_rpc.create_wallet(wallet_name, Some(false)).unwrap();
let rpc_url = format!("{}{}{}", RPCBASE, "/wallet/", wallet_name);
Client::new(rpc_url, auth).unwrap()
}

fn init() -> (Client, Client, Box<dyn Fn(u64) -> ()>) {
let auth = Auth::UserPass(
"testuser".to_string(),
"lq6zequb-gYTdF2_ZEUtr8ywTXzLYtknzWU4nV8uVoo=".to_string(),
);
let rpc = Client::new(RPCBASE.to_string(), auth.clone()).unwrap();

let local_rpc = get_new_wallet_rpc(&rpc, LOCALPARTY, auth.clone());
let remote_rpc = get_new_wallet_rpc(&rpc, REMOTEPARTY, auth.clone());
let sink_rpc = get_new_wallet_rpc(&rpc, SINK, auth.clone());

let local_address = local_rpc
.get_new_address(None, Some(AddressType::Bech32))
.unwrap();
let remote_address = remote_rpc
.get_new_address(None, Some(AddressType::Bech32))
.unwrap();
let sink_address = sink_rpc
.get_new_address(None, Some(AddressType::Bech32))
.unwrap();

sink_rpc.generate_to_address(1, &local_address).unwrap();
sink_rpc.generate_to_address(1, &remote_address).unwrap();
sink_rpc.generate_to_address(100, &sink_address).unwrap();

(
local_rpc,
remote_rpc,
Box::new(move |nb_blocks| {
sink_rpc
.generate_to_address(nb_blocks, &sink_address)
.unwrap();
}),
)
}

fn generate_dlc_parameters<'a, C: secp256k1::Signing>(
rpc: &Client,
secp: &secp256k1::Secp256k1<C>,
collateral: u64,
) -> (PartyParams, PrivateKey, PrivateKey) {
let change_address = rpc
.get_new_address(None, Some(AddressType::Bech32))
.unwrap();
let final_address = rpc
.get_new_address(None, Some(AddressType::Bech32))
.unwrap();
let fund_address = rpc
.get_new_address(None, Some(AddressType::Bech32))
.unwrap();
let fund_priv_key = rpc.dump_private_key(&fund_address).unwrap();
let mut utxos = rpc
.list_unspent(None, None, None, Some(false), None)
.unwrap();
let utxo = utxos.pop().unwrap();
let input_sk = {
let address = utxo.address.clone().unwrap();
rpc.dump_private_key(&address).unwrap()
};
(
PartyParams {
fund_pubkey: fund_priv_key.public_key(&secp),
change_address: change_address,
final_address: final_address,
inputs: vec![TxInputInfo {
outpoint: OutPoint {
txid: utxo.txid,
vout: utxo.vout,
},
input_type: InputType::P2WPKH,
}],
input_amount: utxo.amount.as_sat(),
collateral,
},
fund_priv_key,
input_sk,
)
}

fn main() {
let secp = secp256k1::Secp256k1::new();
let oracle_sk = PrivateKey {
key: secp256k1::SecretKey::new(&mut secp256k1::rand::thread_rng()),
compressed: true,
network: Network::Regtest,
};
let oracle_pubkey = oracle_sk.public_key(&secp);
let oracle_k_value = PrivateKey {
key: secp256k1::SecretKey::new(&mut secp256k1::rand::thread_rng()),
compressed: true,
network: Network::Regtest,
};
let oracle_r_value = oracle_k_value.public_key(&secp);
let (local_rpc, remote_rpc, generate_blocks) = init();

let (local_params, local_fund_sk, local_input_sk) =
generate_dlc_parameters(&local_rpc, &secp, PARTY_COLLATERAL);
let (remote_params, remote_fund_sk, remote_input_sk) =
generate_dlc_parameters(&remote_rpc, &secp, PARTY_COLLATERAL);

let mut dlc_txs =
dlc::create_dlc_transactions(&local_params, &remote_params, &outcomes(), 0, 2, 0)
.expect("Error creating dlc transactions.");

let funding_script_pubkey =
dlc::make_funding_redeemscript(&local_params.fund_pubkey, &remote_params.fund_pubkey);
let fund_output_value = dlc_txs.fund.output[0].value;
let msgs = hashed_msg();
let remote_sig = {
let mut local_cets_sigs = dlc_txs.cets.iter().zip(&msgs).map(|z| {
(
z,
dlc::create_cet_adaptor_sig(
&secp,
&z.0,
&oracle_pubkey,
&oracle_r_value.key.into(),
&local_fund_sk,
&funding_script_pubkey,
fund_output_value,
z.1,
)
.expect("Error creating adaptor sig"),
)
});
let mut remote_cets_sigs = dlc_txs.cets.iter().zip(&msgs).map(|z| {
(
z,
dlc::create_cet_adaptor_sig(
&secp,
&z.0,
&oracle_pubkey,
&oracle_r_value.key.into(),
&remote_fund_sk,
&funding_script_pubkey,
fund_output_value,
z.1,
)
.expect("Error creating adaptor sig"),
)
});

assert!(local_cets_sigs.all(|z| dlc::verify_cet_adaptor_sig(
&secp,
&(z.1).0,
&(z.1).1,
&(z.0).0,
&oracle_pubkey,
&oracle_r_value.key.into(),
&local_params.fund_pubkey,
&funding_script_pubkey,
fund_output_value,
&(z.0).1
)
.is_ok()));

assert!(remote_cets_sigs
.clone()
.all(|z| dlc::verify_cet_adaptor_sig(
&secp,
&(z.1).0,
&(z.1).1,
&(z.0).0,
&oracle_pubkey,
&oracle_r_value.key.into(),
&remote_params.fund_pubkey,
&funding_script_pubkey,
fund_output_value,
&(z.0).1
)
.is_ok()));
remote_cets_sigs.nth(0).unwrap().1
};

let oracle_sig = secp
.schnorr_sign_with_nonce(&msgs[0], &oracle_sk.key, &oracle_k_value.key.into())
.expect("Error creating oracle signature.");

assert!(dlc::sign_cet(
&secp,
&mut dlc_txs.cets[0],
&remote_sig.0,
&oracle_sig,
&local_fund_sk,
&funding_script_pubkey,
fund_output_value,
true,
)
.is_ok());

dlc::util::sign_p2wpkh_input(
&secp,
&local_input_sk,
&mut dlc_txs.fund,
0,
&Address::p2pkh(&local_input_sk.public_key(&secp), Network::Regtest).script_pubkey(),
SigHashType::All,
local_params.input_amount,
);

dlc::util::sign_p2wpkh_input(
&secp,
&remote_input_sk,
&mut dlc_txs.fund,
1,
&Address::p2pkh(&remote_input_sk.public_key(&secp), Network::Regtest).script_pubkey(),
SigHashType::All,
remote_params.input_amount,
);

assert!(local_rpc.send_raw_transaction(&dlc_txs.fund).is_ok());

generate_blocks(1);

assert!(local_rpc.send_raw_transaction(&dlc_txs.cets[0]).is_ok());
}
7 changes: 7 additions & 0 deletions scripts/start_node.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
: "${BITCOINVERSION:=0.20.0}"
docker run --rm -d -p 18443:18443 --name bitcoin-node ruimarinho/bitcoin-core:$BITCOINVERSION \
-regtest=1 \
-rpcallowip=0.0.0/0 \
-rpcbind=0.0.0.0 \
-rpcauth='testuser:ea8070e0acccb49670309dd6c7812e16$2a3487173f9f6b603d43a70e6ccb0aa671a16dbee1cf86b098e77532d2515370' \
-addresstype=bech32
1 change: 1 addition & 0 deletions scripts/stop_node.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker stop bitcoin-node

0 comments on commit 8fda81b

Please sign in to comment.