Update dependencies

- Add toolchain
- Common:
  - bitcoin v0.32.0;
  - lightning v0.1.0
- TEOS:
  - bitcoin v0.32.0;
  - bitcoincore-rpc v0.19.0;
  - lightning v0.1.0;
  - lightning-net-tokio v0.1.0;
  - lightning-block-sync v0.1.0
- Watchtower-Plugin:
  - bitcoin v0.32.0;
  - cln-plugin v0.3.0
This commit is contained in:
dzdidi 2025-01-30 13:50:57 +01:00
parent 4e47db227e
commit b3a621a781
No known key found for this signature in database
GPG key ID: 1FFF5A7760BD933D
26 changed files with 1649 additions and 1281 deletions

View file

@ -8,7 +8,7 @@ on:
env:
bitcoind_version: "27.0"
cln_version: "24.02.2"
cln_version: "24.11.1"
jobs:
cache-cln:
@ -53,6 +53,11 @@ jobs:
- uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.81.0
components: rustfmt, clippy
- name: Install bitcoind
run: |
wget https://bitcoincore.org/bin/bitcoin-core-${{ env.bitcoind_version }}/bitcoin-${{ env.bitcoind_version }}-x86_64-linux-gnu.tar.gz
@ -66,9 +71,10 @@ jobs:
with:
path: lightning
key: ${{ runner.os }}-build-${{ env.cache-name }}-v${{ env.cln_version }}
- name: Link CLN
run: |
cd lightning && sudo make install
- name: Link CLN
run: |
source $HOME/.cargo/env
cd lightning && sudo make install
- name: Install teos and the plugin
run: |
cargo install --locked --path teos

2188
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -5,4 +5,4 @@ members = [
"teos",
"teos-common",
"watchtower-plugin"
]
]

View file

@ -6,7 +6,7 @@
- `bitcoind`
### Minimum Supported Rust Version (MSRV)
FIXME: Define MSRV
Refer to [toolchain](./rust-toolchain.toml)
### Installing Rust
Refer to [rust-lang.org](https://www.rust-lang.org/tools/install).

6
rust-toolchain.toml Normal file
View file

@ -0,0 +1,6 @@
[toolchain]
channel = "1.81.0"
components = [
"rustfmt",
"clippy",
]

View file

@ -20,8 +20,8 @@ rand = "0.8.4"
chacha20poly1305 = "0.8.0"
# Bitcoin and Lightning
bitcoin = { version = "0.28.0", features = [ "use-serde" ] }
lightning = "0.0.108"
bitcoin = { version = "0.32.0", features = [ "serde" ] }
lightning = "0.1.0"
[build-dependencies]
tonic-build = "0.11"
tonic-build = "0.11"

View file

@ -1,10 +1,9 @@
//! Cryptography module, used in the interaction between users and towers.
use rand::distributions::Uniform;
use rand::Rng;
use chacha20poly1305::aead::{Aead, NewAead};
use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce};
use rand::distributions::Uniform;
use rand::Rng;
use bitcoin::consensus;
use bitcoin::hashes::{sha256, Hash};
@ -20,7 +19,7 @@ pub enum DecryptingError {
}
/// Shadows [message_signing::sign].
pub fn sign(msg: &[u8], sk: &SecretKey) -> Result<String, Error> {
pub fn sign(msg: &[u8], sk: &SecretKey) -> String {
message_signing::sign(msg, sk)
}
@ -47,8 +46,8 @@ pub fn encrypt(
) -> Result<Vec<u8>, chacha20poly1305::aead::Error> {
// Defaults is [0; 12]
let nonce = Nonce::default();
let _k = sha256::Hash::hash(secret);
let key = Key::from_slice(&_k);
let k = sha256::Hash::hash(secret.as_byte_array());
let key = Key::from_slice(k.as_byte_array());
let cypher = ChaCha20Poly1305::new(key);
cypher.encrypt(&nonce, consensus::serialize(message).as_ref())
@ -64,8 +63,8 @@ pub fn encrypt(
pub fn decrypt(encrypted_blob: &[u8], secret: &Txid) -> Result<Transaction, DecryptingError> {
// Defaults is [0; 12]
let nonce = Nonce::default();
let _k = sha256::Hash::hash(secret);
let key = Key::from_slice(&_k);
let k = sha256::Hash::hash(secret.as_byte_array());
let key = Key::from_slice(k.as_byte_array());
let cypher = ChaCha20Poly1305::new(key);
@ -95,6 +94,8 @@ pub fn get_random_keypair() -> (SecretKey, PublicKey) {
#[cfg(test)]
mod tests {
use std::str::FromStr;
use super::*;
use bitcoin::consensus;
use bitcoin::hashes::hex::FromHex;
@ -108,8 +109,8 @@ mod tests {
let expected_enc_blob = Vec::from_hex(ENC_BLOB).unwrap();
let tx_bytes = Vec::from_hex(HEX_TX).unwrap();
let tx = consensus::deserialize(&tx_bytes).unwrap();
let txid = Txid::from_hex(HEX_TXID).unwrap();
let tx: Transaction = consensus::deserialize(&tx_bytes).unwrap();
let txid = bitcoin::Txid::from_str(HEX_TXID).unwrap();
assert_eq!(encrypt(&tx, &txid).unwrap(), expected_enc_blob);
}
@ -118,7 +119,7 @@ mod tests {
let expected_tx = consensus::deserialize(&Vec::from_hex(HEX_TX).unwrap()).unwrap();
let encrypted_blob = Vec::from_hex(ENC_BLOB).unwrap();
let txid = Txid::from_hex(HEX_TXID).unwrap();
let txid = bitcoin::Txid::from_str(HEX_TXID).unwrap();
assert_eq!(decrypt(&encrypted_blob, &txid).unwrap(), expected_tx);
}
}

View file

@ -92,8 +92,7 @@ impl RegistrationReceipt {
}
pub fn sign(&mut self, sk: &SecretKey) {
// TODO: Check if there's any case where this can actually fail. Don't unwrap if so.
self.signature = Some(cryptography::sign(&self.to_vec(), sk).unwrap());
self.signature = Some(cryptography::sign(&self.to_vec(), sk));
}
pub fn verify(&self, id: &UserId) -> bool {
@ -153,8 +152,7 @@ impl AppointmentReceipt {
}
pub fn sign(&mut self, sk: &SecretKey) {
// TODO: Check if there's any case where this can actually fail. Don't unwrap if so.
self.signature = Some(cryptography::sign(&self.to_vec(), sk).unwrap());
self.signature = Some(cryptography::sign(&self.to_vec(), sk));
}
pub fn verify(&self, id: &UserId) -> bool {

View file

@ -1,5 +1,6 @@
use std::convert::TryInto;
use bitcoin::script::PushBytesBuf;
use hex::FromHex;
use rand::distributions::Standard;
use rand::prelude::Distribution;
@ -7,7 +8,7 @@ use rand::Rng;
use bitcoin::hashes::Hash;
use bitcoin::secp256k1::SecretKey;
use bitcoin::{consensus, Script, Transaction, TxOut, Txid};
use bitcoin::{consensus, Amount, ScriptBuf, Transaction, TxOut, Txid};
use crate::appointment::{Appointment, Locator};
use crate::cryptography;
@ -48,13 +49,16 @@ pub fn generate_random_appointment(dispute_txid: Option<&Txid>) -> Appointment {
let tx_bytes = Vec::from_hex(TX_HEX).unwrap();
let mut penalty_tx: Transaction = consensus::deserialize(&tx_bytes).unwrap();
let size = get_random_int::<usize>() % 81;
let mut push_bytes_buf = PushBytesBuf::new();
PushBytesBuf::extend_from_slice(&mut push_bytes_buf, &cryptography::get_random_bytes(size))
.unwrap();
let script_pubkey = ScriptBuf::new_op_return(push_bytes_buf);
// Append a random-sized OP_RETURN to make each transcation random in size.
penalty_tx.output.push(TxOut {
value: 0,
script_pubkey: Script::new_op_return(&cryptography::get_random_bytes(
get_random_int::<usize>() % 81,
)),
value: Amount::from_sat(0),
script_pubkey,
});
let mut raw_locator: [u8; 16] = cryptography::get_random_bytes(16).try_into().unwrap();

View file

@ -32,13 +32,14 @@ tokio = { version = "1.5", features = [ "rt-multi-thread" ] }
triggered = "0.1.2"
warp = "0.3.5"
torut = "0.2.1"
base64 = "0.22.1"
# Bitcoin and Lightning
bitcoin = { version = "0.28.0", features = [ "base64" ] }
bitcoincore-rpc = "0.15.0"
lightning = "0.0.108"
lightning-net-tokio = "0.0.108"
lightning-block-sync = { version = "0.0.108", features = [ "rpc-client" ] }
bitcoin = { version = "0.32.0" }
bitcoincore-rpc = "0.19.0"
lightning = "0.1.0"
lightning-net-tokio = "0.1.0"
lightning-block-sync = { version = "0.1.0", features = [ "rpc-client" ] }
# Local
teos-common = { path = "../teos-common" }

View file

@ -767,7 +767,7 @@ mod tests_methods {
// Then try to add an appointment
let appointment = generate_dummy_appointment(None).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
let response = request_to_api::<
common_msgs::AddAppointmentRequest,
@ -793,7 +793,7 @@ mod tests_methods {
let (server_addr, _s) = run_tower_in_background().await;
let (user_sk, _s) = cryptography::get_random_keypair();
let appointment = generate_dummy_appointment(None).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
assert_eq!(
check_api_error(
@ -845,8 +845,8 @@ mod tests_methods {
.add_dummy_tracker_to_responder(&tracker);
// Try to add it via the http API
let appointment = generate_dummy_appointment(Some(&dispute_tx.txid())).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let appointment = generate_dummy_appointment(Some(&dispute_tx.compute_txid())).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
assert_eq!(
check_api_error(
Endpoint::AddAppointment,
@ -875,7 +875,7 @@ mod tests_methods {
.await;
let (user_sk, _) = cryptography::get_random_keypair();
let appointment = generate_dummy_appointment(None).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
assert_eq!(
check_api_error(
@ -915,7 +915,7 @@ mod tests_methods {
// Add an appointment
let appointment = generate_dummy_appointment(None).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
request_to_api::<common_msgs::AddAppointmentRequest, common_msgs::AddAppointmentResponse>(
Endpoint::AddAppointment,
@ -939,8 +939,7 @@ mod tests_methods {
signature: cryptography::sign(
format!("get appointment {}", appointment.locator).as_bytes(),
&user_sk,
)
.unwrap(),
),
},
server_addr,
)
@ -970,7 +969,6 @@ mod tests_methods {
format!("get appointment {}", appointment.locator).as_bytes(),
&user_sk,
)
.unwrap()
})),
server_addr,
)
@ -1013,7 +1011,6 @@ mod tests_methods {
format!("get appointment {}", appointment.locator).as_bytes(),
&user_sk,
)
.unwrap()
})),
server_addr,
)
@ -1048,7 +1045,6 @@ mod tests_methods {
format!("get appointment {}", appointment.locator).as_bytes(),
&user_sk,
)
.unwrap()
})),
server_addr,
)
@ -1086,8 +1082,7 @@ mod tests_methods {
>(
Endpoint::GetSubscriptionInfo,
common_msgs::GetSubscriptionInfoRequest {
signature: cryptography::sign("get subscription info".as_bytes(), &user_sk)
.unwrap(),
signature: cryptography::sign("get subscription info".as_bytes(), &user_sk),
},
server_addr,
)
@ -1111,7 +1106,6 @@ mod tests_methods {
Endpoint::GetSubscriptionInfo,
RequestBody::Json(serde_json::json!(common_msgs::GetSubscriptionInfoRequest {
signature: cryptography::sign("get subscription info".as_bytes(), &user_sk)
.unwrap(),
})),
server_addr,
)
@ -1139,7 +1133,6 @@ mod tests_methods {
Endpoint::GetSubscriptionInfo,
RequestBody::Json(serde_json::json!(common_msgs::GetSubscriptionInfoRequest {
signature: cryptography::sign("get subscription info".as_bytes(), &user_sk)
.unwrap(),
})),
server_addr,
)

View file

@ -466,7 +466,7 @@ mod tests_private_api {
internal_api.watcher.register(UserId(user_pk)).unwrap();
let appointment = generate_dummy_appointment(None).inner;
let user_signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let user_signature = cryptography::sign(&appointment.to_vec(), &user_sk);
internal_api
.watcher
.add_appointment(appointment.clone(), user_signature)
@ -509,7 +509,7 @@ mod tests_private_api {
async fn test_get_appointments() {
let (internal_api, _s) = create_api().await;
let locator = Locator::new(get_random_tx().txid()).to_vec();
let locator = Locator::new(get_random_tx().compute_txid()).to_vec();
let response = internal_api
.get_appointments(Request::new(msgs::GetAppointmentsRequest { locator }))
.await
@ -525,7 +525,7 @@ mod tests_private_api {
for i in 0..3 {
// Create a dispute tx to be used for creating different dummy appointments with the same locator.
let dispute_txid = get_random_tx().txid();
let dispute_txid = get_random_tx().compute_txid();
// The number of different appointments to create for this dispute tx.
let appointments_to_create = 4 * i + 7;
@ -535,7 +535,7 @@ mod tests_private_api {
let (user_sk, user_pk) = get_random_keypair();
internal_api.watcher.register(UserId(user_pk)).unwrap();
let appointment = generate_dummy_appointment(Some(&dispute_txid)).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
internal_api
.watcher
.add_appointment(appointment, signature)
@ -593,7 +593,7 @@ mod tests_private_api {
.add_dummy_tracker_to_responder(&tracker);
}
let locator = Locator::new(dispute_tx.txid());
let locator = Locator::new(dispute_tx.compute_txid());
// Query for the current locator and assert it retrieves correct trackers.
let response = internal_api
@ -648,7 +648,7 @@ mod tests_private_api {
// Add data to the Watcher
for _ in 0..2 {
let appointment = generate_dummy_appointment(None).inner;
let user_signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let user_signature = cryptography::sign(&appointment.to_vec(), &user_sk);
internal_api
.watcher
.add_appointment(appointment.clone(), user_signature)
@ -731,7 +731,7 @@ mod tests_private_api {
// Add an appointment and check back
let (uuid, appointment) = generate_dummy_appointment_with_user(user_id, None);
let user_signature = cryptography::sign(&appointment.inner.to_vec(), &user_sk).unwrap();
let user_signature = cryptography::sign(&appointment.inner.to_vec(), &user_sk);
internal_api
.watcher
.add_appointment(appointment.inner, user_signature)
@ -901,7 +901,7 @@ mod tests_public_api {
internal_api.watcher.register(UserId(user_pk)).unwrap();
let appointment = generate_dummy_appointment(None).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
let response = internal_api
.add_appointment(Request::new(common_msgs::AddAppointmentRequest {
@ -926,7 +926,7 @@ mod tests_public_api {
let (user_sk, _) = get_random_keypair();
let appointment = generate_dummy_appointment(None).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
match internal_api
.add_appointment(Request::new(common_msgs::AddAppointmentRequest {
@ -955,7 +955,7 @@ mod tests_public_api {
internal_api.watcher.register(UserId(user_pk)).unwrap();
let appointment = generate_dummy_appointment(None).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
match internal_api
.add_appointment(Request::new(common_msgs::AddAppointmentRequest {
@ -984,7 +984,7 @@ mod tests_public_api {
internal_api.watcher.register(UserId(user_pk)).unwrap();
let appointment = generate_dummy_appointment(None).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
match internal_api
.add_appointment(Request::new(common_msgs::AddAppointmentRequest {
@ -1021,8 +1021,8 @@ mod tests_public_api {
.add_dummy_tracker_to_responder(&tracker);
// Try to add it again using the API.
let appointment = generate_dummy_appointment(Some(&dispute_tx.txid())).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let appointment = generate_dummy_appointment(Some(&dispute_tx.compute_txid())).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
match internal_api
.add_appointment(Request::new(common_msgs::AddAppointmentRequest {
appointment: Some(appointment.into()),
@ -1047,7 +1047,7 @@ mod tests_public_api {
let (user_sk, _) = get_random_keypair();
let appointment = generate_dummy_appointment(None).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
match internal_api
.add_appointment(Request::new(common_msgs::AddAppointmentRequest {
@ -1074,7 +1074,7 @@ mod tests_public_api {
// Add the appointment
let appointment = generate_dummy_appointment(None).inner;
let user_signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let user_signature = cryptography::sign(&appointment.to_vec(), &user_sk);
internal_api
.watcher
.add_appointment(appointment.clone(), user_signature)
@ -1085,7 +1085,7 @@ mod tests_public_api {
let response = internal_api
.get_appointment(Request::new(common_msgs::GetAppointmentRequest {
locator: appointment.locator.to_vec(),
signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(),
signature: cryptography::sign(message.as_bytes(), &user_sk),
}))
.await
.unwrap()
@ -1113,7 +1113,7 @@ mod tests_public_api {
match internal_api
.get_appointment(Request::new(common_msgs::GetAppointmentRequest {
locator: appointment.locator.to_vec(),
signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(),
signature: cryptography::sign(message.as_bytes(), &user_sk),
}))
.await
{
@ -1140,7 +1140,7 @@ mod tests_public_api {
match internal_api
.get_appointment(Request::new(common_msgs::GetAppointmentRequest {
locator: appointment.locator.to_vec(),
signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(),
signature: cryptography::sign(message.as_bytes(), &user_sk),
}))
.await
{
@ -1168,7 +1168,7 @@ mod tests_public_api {
match internal_api
.get_appointment(Request::new(common_msgs::GetAppointmentRequest {
locator: appointment.locator.to_vec(),
signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(),
signature: cryptography::sign(message.as_bytes(), &user_sk),
}))
.await
{
@ -1191,7 +1191,7 @@ mod tests_public_api {
match internal_api
.get_appointment(Request::new(common_msgs::GetAppointmentRequest {
locator: appointment.locator.to_vec(),
signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(),
signature: cryptography::sign(message.as_bytes(), &user_sk),
}))
.await
{
@ -1215,7 +1215,7 @@ mod tests_public_api {
let message = "get subscription info".to_string();
let response = internal_api
.get_subscription_info(Request::new(common_msgs::GetSubscriptionInfoRequest {
signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(),
signature: cryptography::sign(message.as_bytes(), &user_sk),
}))
.await
.unwrap()
@ -1238,7 +1238,7 @@ mod tests_public_api {
let message = "get subscription info".to_string();
match internal_api
.get_subscription_info(Request::new(common_msgs::GetSubscriptionInfoRequest {
signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(),
signature: cryptography::sign(message.as_bytes(), &user_sk),
}))
.await
{
@ -1262,7 +1262,7 @@ mod tests_public_api {
let message = "get subscription info".to_string();
match internal_api
.get_subscription_info(Request::new(common_msgs::GetSubscriptionInfoRequest {
signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(),
signature: cryptography::sign(message.as_bytes(), &user_sk),
}))
.await
{
@ -1283,7 +1283,7 @@ mod tests_public_api {
let message = "get subscription info".to_string();
match internal_api
.get_subscription_info(Request::new(common_msgs::GetSubscriptionInfoRequest {
signature: cryptography::sign(message.as_bytes(), &user_sk).unwrap(),
signature: cryptography::sign(message.as_bytes(), &user_sk),
}))
.await
{

View file

@ -9,20 +9,19 @@
* at your option.
*/
use base64::{engine::general_purpose::URL_SAFE as BASE64, Engine};
use std::convert::TryInto;
use std::io::{Error, ErrorKind};
use std::sync::Arc;
use tokio::sync::Mutex;
use bitcoin::base64;
use bitcoin::hash_types::{BlockHash, Txid};
use bitcoin::hashes::hex::ToHex;
use bitcoin::{Block, Transaction};
use bitcoincore_rpc::Auth;
use bitcoin::Transaction;
use bitcoincore_rpc::{Auth, RawTx};
use lightning::util::ser::Writeable;
use lightning_block_sync::http::{HttpEndpoint, JsonResponse};
use lightning_block_sync::rpc::RpcClient;
use lightning_block_sync::{AsyncBlockSourceResult, BlockHeaderData, BlockSource};
use lightning_block_sync::{AsyncBlockSourceResult, BlockData, BlockHeaderData, BlockSource};
/// A simple implementation of a bitcoind client (`bitcoin-cli`) with the minimal functionality required by the tower.
pub struct BitcoindClient<'a> {
@ -52,7 +51,10 @@ impl BlockSource for &BitcoindClient<'_> {
}
/// Gets a block given its hash.
fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> {
fn get_block<'a>(
&'a self,
header_hash: &'a BlockHash,
) -> AsyncBlockSourceResult<'a, BlockData> {
Box::pin(async move {
let rpc = self.bitcoind_rpc_client.lock().await;
rpc.get_block(header_hash).await
@ -101,8 +103,8 @@ impl<'a> BitcoindClient<'a> {
}
}?;
let rpc_credentials = base64::encode(&format!("{}:{}", rpc_user, rpc_password));
let bitcoind_rpc_client = RpcClient::new(&rpc_credentials, http_endpoint)?;
let rpc_credentials = BASE64.encode(format!("{}:{}", rpc_user, rpc_password));
let bitcoind_rpc_client = RpcClient::new(&rpc_credentials, http_endpoint);
let client = Self {
bitcoind_rpc_client: Arc::new(Mutex::new(bitcoind_rpc_client)),
@ -127,9 +129,10 @@ impl<'a> BitcoindClient<'a> {
}
/// Gets a fresh RPC client.
pub fn get_new_rpc_client(&self) -> std::io::Result<RpcClient> {
pub fn get_new_rpc_client(&self) -> RpcClient {
let http_endpoint = HttpEndpoint::for_host(self.host.to_owned()).with_port(self.port);
let rpc_credentials = base64::encode(&format!("{}:{}", self.rpc_user, self.rpc_password));
let rpc_credentials = BASE64.encode(format!("{}:{}", self.rpc_user, self.rpc_password));
RpcClient::new(&rpc_credentials, http_endpoint)
}
@ -146,7 +149,7 @@ impl<'a> BitcoindClient<'a> {
pub async fn send_raw_transaction(&self, raw_tx: &Transaction) -> Result<Txid, std::io::Error> {
let rpc = self.bitcoind_rpc_client.lock().await;
let raw_tx_json = serde_json::json!(raw_tx.encode().to_hex());
let raw_tx_json = serde_json::json!(raw_tx.encode().raw_hex());
rpc.call_method::<Txid>("sendrawtransaction", &[raw_tx_json])
.await
}
@ -155,7 +158,7 @@ impl<'a> BitcoindClient<'a> {
pub async fn get_raw_transaction(&self, txid: &Txid) -> Result<Transaction, std::io::Error> {
let rpc = self.bitcoind_rpc_client.lock().await;
let txid_hex = serde_json::json!(txid.encode().to_hex());
let txid_hex = serde_json::json!(txid.encode().raw_hex());
rpc.call_method::<Transaction>("getrawtransaction", &[txid_hex])
.await
}

View file

@ -80,17 +80,17 @@ impl Carrier {
pub(crate) fn send_transaction(&mut self, tx: &Transaction) -> ConfirmationStatus {
self.hang_until_bitcoind_reachable();
if let Some(receipt) = self.issued_receipts.get(&tx.txid()) {
log::info!("Transaction already sent: {}", tx.txid());
if let Some(receipt) = self.issued_receipts.get(&tx.compute_txid()) {
log::info!("Transaction already sent: {}", tx.compute_txid());
return *receipt;
}
log::info!("Pushing transaction to the network: {}", tx.txid());
log::info!("Pushing transaction to the network: {}", tx.compute_txid());
let receipt = match self.bitcoin_cli.send_raw_transaction(tx) {
Ok(_) => {
// Here the transaction could, potentially, have been in mempool before the current height.
// This shouldn't really matter though.
log::info!("Transaction successfully delivered: {}", tx.txid());
log::info!("Transaction successfully delivered: {}", tx.compute_txid());
ConfirmationStatus::InMempoolSince(self.block_height)
}
Err(JsonRpcError(RpcError(rpcerr))) => match rpcerr.code {
@ -106,7 +106,7 @@ impl Carrier {
rpc_errors::RPC_VERIFY_ALREADY_IN_CHAIN => {
log::info!(
"Transaction was confirmed long ago, not keeping track of it: {}",
tx.txid()
tx.compute_txid()
);
// Given we are not using txindex, if a transaction bounces we cannot get its confirmation count. However, [send_transaction] is guarded by
@ -117,7 +117,7 @@ impl Carrier {
rpc_errors::RPC_DESERIALIZATION_ERROR => {
// Adding this here just for completeness. We should never end up here. The Carrier only sends txs handed by the Responder,
// who receives them from the Watcher, who checks that the tx can be properly deserialized.
log::info!("Transaction cannot be deserialized: {}", tx.txid());
log::info!("Transaction cannot be deserialized: {}", tx.compute_txid());
ConfirmationStatus::Rejected(rpc_errors::RPC_DESERIALIZATION_ERROR)
}
_ => {
@ -139,7 +139,7 @@ impl Carrier {
}
};
self.issued_receipts.insert(tx.txid(), receipt);
self.issued_receipts.insert(tx.compute_txid(), receipt);
receipt
}
@ -184,6 +184,7 @@ impl Carrier {
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
use std::thread;
use crate::test_utils::{get_random_tx, start_server, BitcoindMock, MockOptions, START_HEIGHT};
@ -217,7 +218,7 @@ mod tests {
// Lets add some dummy data into the cache
for i in 0..10 {
carrier.issued_receipts.insert(
get_random_tx().txid(),
get_random_tx().compute_txid(),
ConfirmationStatus::ConfirmedIn(start_height - i),
);
}
@ -243,7 +244,7 @@ mod tests {
assert_eq!(r, ConfirmationStatus::InMempoolSince(start_height));
// Check the receipt is on the cache
assert_eq!(carrier.issued_receipts.get(&tx.txid()).unwrap(), &r);
assert_eq!(carrier.issued_receipts.get(&tx.compute_txid()).unwrap(), &r);
}
#[test]
@ -261,7 +262,7 @@ mod tests {
assert_eq!(r, ConfirmationStatus::InMempoolSince(start_height));
// Check the receipt is on the cache
assert_eq!(carrier.issued_receipts.get(&tx.txid()).unwrap(), &r);
assert_eq!(carrier.issued_receipts.get(&tx.compute_txid()).unwrap(), &r);
}
#[test]
@ -284,7 +285,7 @@ mod tests {
);
// Check the receipt is on the cache
assert_eq!(carrier.issued_receipts.get(&tx.txid()).unwrap(), &r);
assert_eq!(carrier.issued_receipts.get(&tx.compute_txid()).unwrap(), &r);
}
#[test]
@ -306,7 +307,7 @@ mod tests {
);
// Check the receipt is on the cache
assert_eq!(carrier.issued_receipts.get(&tx.txid()).unwrap(), &r);
assert_eq!(carrier.issued_receipts.get(&tx.compute_txid()).unwrap(), &r);
}
#[test]
@ -326,7 +327,7 @@ mod tests {
assert_eq!(r, ConfirmationStatus::IrrevocablyResolved);
// Check the receipt is on the cache
assert_eq!(carrier.issued_receipts.get(&tx.txid()).unwrap(), &r);
assert_eq!(carrier.issued_receipts.get(&tx.compute_txid()).unwrap(), &r);
}
#[test]
@ -348,7 +349,7 @@ mod tests {
);
// Check the receipt is on the cache
assert_eq!(carrier.issued_receipts.get(&tx.txid()).unwrap(), &r);
assert_eq!(carrier.issued_receipts.get(&tx.compute_txid()).unwrap(), &r);
}
#[test]
@ -389,7 +390,7 @@ mod tests {
start_server(bitcoind_mock.server);
let carrier = Carrier::new(bitcoin_cli, bitcoind_reachable, start_height);
let txid = Txid::from_hex(TXID_HEX).unwrap();
let txid = Txid::from_str(TXID_HEX).unwrap();
assert!(carrier.in_mempool(&txid));
}
@ -402,7 +403,7 @@ mod tests {
start_server(bitcoind_mock.server);
let carrier = Carrier::new(bitcoin_cli, bitcoind_reachable, start_height);
let txid = Txid::from_hex(TXID_HEX).unwrap();
let txid = Txid::from_str(TXID_HEX).unwrap();
assert!(!carrier.in_mempool(&txid));
}
@ -417,7 +418,7 @@ mod tests {
start_server(bitcoind_mock.server);
let carrier = Carrier::new(bitcoin_cli, bitcoind_reachable, start_height);
let txid = Txid::from_hex(TXID_HEX).unwrap();
let txid = Txid::from_str(TXID_HEX).unwrap();
assert!(!carrier.in_mempool(&txid));
}
@ -431,7 +432,7 @@ mod tests {
start_server(bitcoind_mock.server);
let carrier = Carrier::new(bitcoin_cli, bitcoind_reachable, start_height);
let txid = Txid::from_hex(TXID_HEX).unwrap();
let txid = Txid::from_str(TXID_HEX).unwrap();
assert!(!carrier.in_mempool(&txid));
}
@ -444,7 +445,7 @@ mod tests {
let start_height = START_HEIGHT as u32;
let carrier = Carrier::new(bitcoin_cli, bitcoind_reachable.clone(), start_height);
let txid = Txid::from_hex(TXID_HEX).unwrap();
let txid = Txid::from_str(TXID_HEX).unwrap();
let delay = std::time::Duration::new(3, 0);
thread::spawn(move || {

View file

@ -26,7 +26,7 @@ where
{
/// A bitcoin client to poll best tips from.
spv_client: SpvClient<'a, P, C, L>,
/// The lat known block header by the [ChainMonitor].
/// The last known block header by the [ChainMonitor].
last_known_block_header: ValidatedBlockHeader,
/// A [DBM] (database manager) instance. Used to persist block data into disk.
dbm: Arc<Mutex<DBM>>,
@ -135,8 +135,8 @@ mod tests {
use std::iter::FromIterator;
use std::thread;
use bitcoin::network::constants::Network;
use bitcoin::BlockHash;
use bitcoin::Network;
use lightning_block_sync::{poll::ChainPoller, SpvClient, UnboundedCache};
use crate::test_utils::{Blockchain, START_HEIGHT};
@ -158,7 +158,7 @@ mod tests {
impl chain::Listen for DummyListener {
fn filtered_block_connected(
&self,
header: &bitcoin::BlockHeader,
header: &bitcoin::block::Header,
_: &chain::transaction::TransactionData,
_: u32,
) {
@ -167,7 +167,7 @@ mod tests {
.insert(header.block_hash());
}
fn block_disconnected(&self, header: &bitcoin::BlockHeader, _: u32) {
fn block_disconnected(&self, header: &bitcoin::block::Header, _: u32) {
self.disconnected_blocks
.borrow_mut()
.insert(header.block_hash());

View file

@ -689,7 +689,7 @@ impl DBM {
// DISCUSS: Should we store the txids to avoid pulling raw txs and deserializing then hashing them.
let penalty_txid = consensus::deserialize::<bitcoin::Transaction>(&raw_penalty_tx)
.unwrap()
.txid();
.compute_txid();
summaries.insert(
UUID::from_slice(&raw_uuid).unwrap(),
PenaltySummary::new(
@ -704,7 +704,7 @@ impl DBM {
/// Stores the last known block into the database.
pub(crate) fn store_last_known_block(&self, block_hash: &BlockHash) -> Result<(), Error> {
let query = "INSERT OR REPLACE INTO last_known_block (id, block_hash) VALUES (0, ?)";
self.store_data(query, params![block_hash.to_vec()])
self.store_data(query, params![block_hash.to_byte_array().to_vec()])
}
/// Loads the last known block from the database.
@ -1130,7 +1130,7 @@ mod tests {
let dbm = DBM::in_memory().unwrap();
let mut appointments = HashMap::new();
let dispute_tx = get_random_tx();
let dispute_txid = dispute_tx.txid();
let dispute_txid = dispute_tx.compute_txid();
let locator = Locator::new(dispute_txid);
for i in 1..11 {
@ -1316,7 +1316,7 @@ mod tests {
let user = UserInfo::new(AVAILABLE_SLOTS, SUBSCRIPTION_START, SUBSCRIPTION_EXPIRY);
let dispute_tx = get_random_tx();
let dispute_txid = dispute_tx.txid();
let dispute_txid = dispute_tx.compute_txid();
let mut uuids = HashSet::new();
// Add ten appointments triggered by the same locator.
@ -1336,7 +1336,7 @@ mod tests {
let user_id = get_random_user_id();
dbm.store_user(user_id, &user).unwrap();
let dispute_txid = get_random_tx().txid();
let dispute_txid = get_random_tx().compute_txid();
let (uuid, appointment) =
generate_dummy_appointment_with_user(user_id, Some(&dispute_txid));
dbm.store_appointment(uuid, &appointment).unwrap();
@ -1516,7 +1516,7 @@ mod tests {
let dbm = DBM::in_memory().unwrap();
let mut trackers = HashMap::new();
let dispute_tx = get_random_tx();
let dispute_txid = dispute_tx.txid();
let dispute_txid = dispute_tx.compute_txid();
let locator = Locator::new(dispute_txid);
let status = ConfirmationStatus::InMempoolSince(42);
@ -1700,8 +1700,10 @@ mod tests {
let tracker = get_random_tracker(user_id, status);
dbm.store_tracker(uuid, &tracker).unwrap();
penalties_summaries
.insert(uuid, PenaltySummary::new(tracker.penalty_tx.txid(), status));
penalties_summaries.insert(
uuid,
PenaltySummary::new(tracker.penalty_tx.compute_txid(), status),
);
}
assert_eq!(dbm.load_penalties_summaries(), penalties_summaries);

View file

@ -23,7 +23,7 @@ impl UUID {
pub fn new(locator: Locator, user_id: UserId) -> Self {
let mut uuid_data = locator.to_vec();
uuid_data.extend(user_id.0.serialize());
UUID(ripemd160::Hash::hash(&uuid_data).into_inner())
UUID(ripemd160::Hash::hash(&uuid_data).to_byte_array())
}
/// Serializes the [UUID] returning its byte representation.

View file

@ -297,7 +297,7 @@ impl chain::Listen for Gatekeeper {
/// This is mainly used to keep track of time and expire / outdate subscriptions when needed.
fn filtered_block_connected(
&self,
header: &bitcoin::BlockHeader,
header: &bitcoin::block::Header,
_: &chain::transaction::TransactionData,
height: u32,
) {
@ -324,7 +324,7 @@ impl chain::Listen for Gatekeeper {
}
/// Handles reorgs in the [Gatekeeper]. Simply updates the last_known_block_height.
fn block_disconnected(&self, header: &bitcoin::BlockHeader, height: u32) {
fn block_disconnected(&self, header: &bitcoin::block::Header, height: u32) {
log::warn!("Block disconnected: {}", header.block_hash());
// There's nothing to be done here but updating the last known block
self.last_known_block_height
@ -435,7 +435,7 @@ mod tests {
// Let's now provide data generated by an actual user, still the user is unknown
let (user_sk, user_pk) = get_random_keypair();
let signature = cryptography::sign(message, &user_sk).unwrap();
let signature = cryptography::sign(message, &user_sk);
assert_eq!(
gatekeeper.authenticate_user(message, &signature),
Err(AuthenticationFailure("User not found."))

View file

@ -3,13 +3,12 @@ use simple_logger::SimpleLogger;
use std::fs;
use std::io::ErrorKind;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use std::sync::{Arc, Condvar, Mutex};
use structopt::StructOpt;
use tokio::task;
use tonic::transport::{Certificate, Server, ServerTlsConfig};
use bitcoin::network::constants::Network;
use bitcoin::network::Network;
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
use bitcoincore_rpc::{Auth, Client, RpcApi};
use lightning_block_sync::init::validate_best_block_header;
@ -259,13 +258,6 @@ async fn main() {
tip.height
);
// This is how chain poller names bitcoin networks.
let btc_network = match conf.btc_network.as_str() {
"main" => "bitcoin",
"test" => "testnet",
any => any,
};
// Build components
let gatekeeper = Arc::new(Gatekeeper::new(
tip.height,
@ -275,7 +267,10 @@ async fn main() {
dbm.clone(),
));
let mut poller = ChainPoller::new(&mut derefed, Network::from_str(btc_network).unwrap());
let mut poller = ChainPoller::new(
&mut derefed,
Network::from_core_arg(&conf.btc_network).unwrap(),
);
let (responder, watcher) = {
let last_n_blocks = get_last_n_blocks(&mut poller, tip, IRREVOCABLY_RESOLVED as usize)
.await.unwrap_or_else(|e| {

View file

@ -3,8 +3,10 @@
use std::collections::HashSet;
use std::sync::{Arc, Mutex};
use bitcoin::hashes::Hash;
use bitcoin::{consensus, BlockHash};
use bitcoin::{BlockHeader, Transaction, Txid};
use bitcoin::{Transaction, Txid};
use lightning::chain;
use lightning_block_sync::poll::ValidatedBlock;
@ -93,8 +95,18 @@ impl TransactionTracker {
impl From<TransactionTracker> for common_msgs::Tracker {
fn from(t: TransactionTracker) -> Self {
common_msgs::Tracker {
dispute_txid: t.dispute_tx.txid().to_vec(),
penalty_txid: t.penalty_tx.txid().to_vec(),
dispute_txid: t
.dispute_tx
.compute_txid()
.to_raw_hash()
.to_byte_array()
.to_vec(),
penalty_txid: t
.penalty_tx
.compute_txid()
.to_raw_hash()
.to_byte_array()
.to_vec(),
penalty_rawtx: consensus::serialize(&t.penalty_tx),
}
}
@ -182,9 +194,9 @@ impl Responder {
let tx_index = self.tx_index.lock().unwrap();
// Check whether the transaction is in mempool or part of our internal txindex. Send it to our node otherwise.
let status = if let Some(block_hash) = tx_index.get(&breach.penalty_tx.txid()) {
let status = if let Some(block_hash) = tx_index.get(&breach.penalty_tx.compute_txid()) {
ConfirmationStatus::ConfirmedIn(tx_index.get_height(block_hash).unwrap() as u32)
} else if carrier.in_mempool(&breach.penalty_tx.txid()) {
} else if carrier.in_mempool(&breach.penalty_tx.compute_txid()) {
// If it's in mempool we assume it was just included
ConfirmationStatus::InMempoolSince(carrier.block_height())
} else {
@ -292,7 +304,7 @@ impl Responder {
// Republish all the dispute transactions of the reorged trackers.
for uuid in reorged_trackers {
let tracker = dbm.load_tracker(uuid).unwrap();
let dispute_txid = tracker.dispute_tx.txid();
let dispute_txid = tracker.dispute_tx.compute_txid();
// Try to publish the dispute transaction.
let should_publish_penalty = match carrier.send_transaction(&tracker.dispute_tx) {
ConfirmationStatus::InMempoolSince(_) => {
@ -368,7 +380,7 @@ impl Responder {
let tracker = dbm.load_tracker(uuid).unwrap();
log::warn!(
"Penalty transaction has missed many confirmations: {}",
tracker.penalty_tx.txid()
tracker.penalty_tx.compute_txid()
);
// Rebroadcast the penalty transaction.
let status = carrier.send_transaction(&tracker.penalty_tx);
@ -401,7 +413,7 @@ impl chain::Listen for Responder {
/// rebroadcasting is performed for those that have missed too many.
fn filtered_block_connected(
&self,
header: &BlockHeader,
header: &bitcoin::block::Header,
txdata: &chain::transaction::TransactionData,
height: u32,
) {
@ -410,7 +422,7 @@ impl chain::Listen for Responder {
let txs = txdata
.iter()
.map(|(_, tx)| (tx.txid(), header.block_hash()))
.map(|(_, tx)| (tx.compute_txid(), header.block_hash()))
.collect();
self.tx_index.lock().unwrap().update(*header, &txs);
@ -444,7 +456,7 @@ impl chain::Listen for Responder {
}
/// Handles reorgs in the [Responder].
fn block_disconnected(&self, header: &BlockHeader, height: u32) {
fn block_disconnected(&self, header: &bitcoin::block::Header, height: u32) {
log::warn!("Block disconnected: {}", header.block_hash());
// Update the carrier and our tx_index.
self.carrier.lock().unwrap().update_height(height);
@ -490,7 +502,7 @@ mod tests {
impl TransactionTracker {
pub fn locator(&self) -> Locator {
Locator::new(self.dispute_tx.txid())
Locator::new(self.dispute_tx.compute_txid())
}
pub fn uuid(&self) -> UUID {
@ -529,7 +541,7 @@ mod tests {
pub(crate) fn add_dummy_tracker(&self, tracker: &TransactionTracker) {
let (_, appointment) = generate_dummy_appointment_with_user(
tracker.user_id,
Some(&tracker.dispute_tx.txid()),
Some(&tracker.dispute_tx.compute_txid()),
);
store_appointment_and_its_user(&self.dbm.lock().unwrap(), &appointment);
self.dbm
@ -712,7 +724,7 @@ mod tests {
let (user_id, uuid) = responder.store_dummy_appointment_to_db();
let breach = get_random_breach();
let penalty_txid = breach.penalty_tx.txid();
let penalty_txid = breach.penalty_tx.compute_txid();
// Add the tx to our txindex
let target_block_hash = *responder.tx_index.lock().unwrap().blocks().get(2).unwrap();
@ -913,7 +925,7 @@ mod tests {
ConfirmationStatus::InMempoolSince(i),
);
just_confirmed.insert(uuid);
txids.insert(breach.penalty_tx.txid());
txids.insert(breach.penalty_tx.compute_txid());
}
2 => {
responder.add_tracker(
@ -1186,7 +1198,7 @@ mod tests {
let user_id = users[i % 2];
let dispute_tx = get_random_tx();
let (uuid, appointment) =
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.txid()));
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.compute_txid()));
responder
.gatekeeper
@ -1214,7 +1226,7 @@ mod tests {
for _ in 0..3 {
let dispute_tx = get_random_tx();
let (uuid, appointment) =
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.txid()));
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.compute_txid()));
responder
.gatekeeper
.add_update_appointment(user_id, uuid, &appointment)
@ -1249,8 +1261,10 @@ mod tests {
let mut just_confirmed_trackers = Vec::new();
for i in 0..10 {
let dispute_tx = get_random_tx();
let (uuid, appointment) =
generate_dummy_appointment_with_user(standalone_user_id, Some(&dispute_tx.txid()));
let (uuid, appointment) = generate_dummy_appointment_with_user(
standalone_user_id,
Some(&dispute_tx.compute_txid()),
);
responder
.gatekeeper
.add_update_appointment(standalone_user_id, uuid, &appointment)
@ -1285,8 +1299,10 @@ mod tests {
let mut trackers_to_rebroadcast = Vec::new();
for _ in 0..5 {
let dispute_tx = get_random_tx();
let (uuid, appointment) =
generate_dummy_appointment_with_user(standalone_user_id, Some(&dispute_tx.txid()));
let (uuid, appointment) = generate_dummy_appointment_with_user(
standalone_user_id,
Some(&dispute_tx.compute_txid()),
);
responder
.gatekeeper
.add_update_appointment(standalone_user_id, uuid, &appointment)
@ -1317,7 +1333,10 @@ mod tests {
.lock()
.unwrap()
.get_issued_receipts()
.insert(get_random_tx().txid(), ConfirmationStatus::ConfirmedIn(21));
.insert(
get_random_tx().compute_txid(),
ConfirmationStatus::ConfirmedIn(21),
);
// Connecting a block should trigger all the state transitions
let block = chain.generate(Some(
@ -1433,7 +1452,7 @@ mod tests {
// Generate appointment and also add it to the DB
let dispute_tx = get_random_tx();
let (uuid, appointment) =
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.txid()));
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.compute_txid()));
responder
.dbm
.lock()

View file

@ -8,6 +8,7 @@
*/
use rand::Rng;
use std::ops::Deref;
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
@ -17,22 +18,24 @@ use jsonrpc_http_server::{CloseHandle, Server, ServerBuilder};
use bitcoincore_rpc::{Auth, Client as BitcoindClient};
use bitcoin::blockdata::block::{Block, BlockHeader};
use bitcoin::block::Block;
use bitcoin::blockdata::constants::genesis_block;
use bitcoin::blockdata::script::{Builder, Script};
use bitcoin::blockdata::script::{Builder, ScriptBuf};
use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxIn, TxOut};
use bitcoin::hash_types::BlockHash;
use bitcoin::hash_types::Txid;
use bitcoin::hashes::Hash;
use bitcoin::network::constants::Network;
use bitcoin::util::hash::bitcoin_merkle_root;
use bitcoin::util::uint::Uint256;
use bitcoin::merkle_tree::calculate_root;
use bitcoin::pow::Work;
use bitcoin::Amount;
use bitcoin::Network;
use bitcoin::Witness;
use lightning_block_sync::poll::{
ChainPoller, Poll, Validate, ValidatedBlock, ValidatedBlockHeader,
};
use lightning_block_sync::{
AsyncBlockSourceResult, BlockHeaderData, BlockSource, BlockSourceError, UnboundedCache,
AsyncBlockSourceResult, BlockData, BlockHeaderData, BlockSource, BlockSourceError,
UnboundedCache,
};
use teos_common::constants::IRREVOCABLY_RESOLVED;
@ -153,8 +156,11 @@ impl Blockchain {
fn at_height_unvalidated(&self, height: usize) -> BlockHeaderData {
assert!(!self.blocks.is_empty());
assert!(height < self.blocks.len());
let height_bytes = height.to_be_bytes();
let mut padded_bytes = [0u8; 32];
padded_bytes[32 - height_bytes.len()..].copy_from_slice(&height_bytes);
BlockHeaderData {
chainwork: self.blocks[0].header.work() + Uint256::from_u64(height as u64).unwrap(),
chainwork: self.blocks[0].header.work() + Work::from_be_bytes(padded_bytes),
height: height as u32,
header: self.blocks[height].header,
}
@ -184,7 +190,7 @@ impl Blockchain {
}
pub fn generate(&mut self, txs: Option<Vec<Transaction>>) -> Block {
let bits = BlockHeader::compact_target_from_u256(&Uint256::from_be_bytes([0xff; 32]));
let bits = bitcoin::Target::from_be_bytes([0xff; 32]).to_compact_lossy();
let prev_block = self.blocks.last().unwrap();
let prev_blockhash = prev_block.block_hash();
@ -199,17 +205,17 @@ impl Blockchain {
}
None => vec![get_random_tx()],
};
let hashes = txdata.iter().map(|obj| obj.txid().as_hash());
let mut header = BlockHeader {
version: 0,
let hashes = txdata.iter().map(|tx| tx.compute_txid().to_raw_hash());
let mut header = bitcoin::block::Header {
version: bitcoin::block::Version::from_consensus(0),
prev_blockhash,
merkle_root: bitcoin_merkle_root(hashes).unwrap().into(),
merkle_root: calculate_root(hashes).unwrap().into(),
time,
bits,
nonce: 0,
};
while header.validate_pow(&header.target()).is_err() {
while header.validate_pow(header.target()).is_err() {
header.nonce += 1;
}
@ -245,7 +251,7 @@ impl BlockSource for Blockchain {
})
}
fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block> {
fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<BlockData> {
Box::pin(async move {
for (height, block) in self.blocks.iter().enumerate() {
if block.header.block_hash() == *header_hash {
@ -254,8 +260,7 @@ impl BlockSource for Blockchain {
return Err(BlockSourceError::persistent("block not found"));
}
}
return Ok(block.clone());
return Ok(BlockData::FullBlock(block.clone()));
}
}
Err(BlockSourceError::transient("block not found"))
@ -289,20 +294,20 @@ pub(crate) fn get_random_tx() -> Transaction {
let prev_txid_bytes = get_random_bytes(32);
Transaction {
version: 2,
lock_time: 0,
version: bitcoin::transaction::Version(2),
lock_time: bitcoin::locktime::absolute::LockTime::from_height(0).unwrap(),
input: vec![TxIn {
previous_output: OutPoint::new(
Txid::from_slice(&prev_txid_bytes).unwrap(),
rng.gen_range(0..200),
),
script_sig: Script::new(),
script_sig: ScriptBuf::new(),
witness: Witness::new(),
sequence: 0,
sequence: bitcoin::Sequence(0),
}],
output: vec![TxOut {
script_pubkey: Builder::new().push_int(1).into_script(),
value: rng.gen_range(0..21000000000),
value: Amount::from_sat(rng.gen_range(0..21_000_000_000)),
}],
}
}
@ -367,6 +372,17 @@ pub(crate) async fn get_last_n_blocks(chain: &mut Blockchain, n: usize) -> Vec<V
last_n_blocks
}
pub(crate) fn get_full_blocks(last_n_blocks: &[ValidatedBlock]) -> Vec<Block> {
last_n_blocks.iter().map(get_full_block).collect()
}
pub(crate) fn get_full_block(block: &ValidatedBlock) -> Block {
match block.deref() {
BlockData::FullBlock(b) => b.clone(),
_ => panic!("Expected FullBlock"),
}
}
pub(crate) enum MockedServerQuery {
Regular,
InMempoool,
@ -405,7 +421,7 @@ pub(crate) async fn create_responder(
let bitcoind_reachable = Arc::new((Mutex::new(true), Condvar::new()));
let carrier = Carrier::new(bitcoin_cli, bitcoind_reachable, height);
Responder::new(&last_n_blocks, height, carrier, gatekeeper, dbm)
Responder::new(last_n_blocks.as_slice(), height, carrier, gatekeeper, dbm)
}
pub(crate) async fn create_watcher(
@ -424,7 +440,7 @@ pub(crate) async fn create_watcher(
Watcher::new(
gatekeeper,
responder,
&last_n_blocks,
last_n_blocks.as_slice(),
chain.get_block_count(),
tower_sk,
tower_id,

View file

@ -1,9 +1,11 @@
use std::collections::{HashMap, VecDeque};
use std::fmt;
use std::hash::Hash;
use std::ops::Deref;
use bitcoin::block::Header;
use bitcoin::hash_types::BlockHash;
use bitcoin::{BlockHeader, Transaction, Txid};
use bitcoin::{Transaction, Txid};
use lightning_block_sync::poll::ValidatedBlock;
use teos_common::appointment::Locator;
@ -110,29 +112,38 @@ where
};
for block in last_n_blocks.iter().rev() {
if let Some(prev_block_hash) = tx_index.blocks.back() {
if block.header.prev_blockhash != *prev_block_hash {
panic!("last_n_blocks contains unchained blocks");
match block.deref() {
lightning_block_sync::BlockData::HeaderOnly(_) => {
panic!("Expected FullBlock")
}
};
lightning_block_sync::BlockData::FullBlock(block) => {
if let Some(prev_block_hash) = tx_index.blocks.back() {
if block.header.prev_blockhash != *prev_block_hash {
panic!("last_n_blocks contains unchained blocks");
}
};
let map = block
.txdata
.iter()
.map(|tx| {
(
K::from_txid(tx.txid()),
match V::get_type() {
Type::Transaction => V::from_data(Data::Transaction(tx.clone())),
Type::BlockHash => {
V::from_data(Data::BlockHash(block.header.block_hash()))
}
},
)
})
.collect();
let map = block
.txdata
.iter()
.map(|tx| {
(
K::from_txid(tx.compute_txid()),
match V::get_type() {
Type::Transaction => {
V::from_data(Data::Transaction(tx.clone()))
}
Type::BlockHash => {
V::from_data(Data::BlockHash(block.header.block_hash()))
}
},
)
})
.collect();
tx_index.update(block.header, &map);
tx_index.update(block.header, &map);
}
}
}
tx_index
@ -155,7 +166,7 @@ where
}
/// Updates the index by adding data from a new block. Removes the oldest block if the index is full afterwards.
pub fn update(&mut self, block_header: BlockHeader, data: &HashMap<K, V>) {
pub fn update(&mut self, block_header: Header, data: &HashMap<K, V>) {
self.blocks.push_back(block_header.block_hash());
let ks = data
@ -218,8 +229,9 @@ mod tests {
use super::*;
use std::ops::Deref;
use crate::test_utils::{get_last_n_blocks, Blockchain};
use crate::test_utils::{get_full_block, get_full_blocks, get_last_n_blocks, Blockchain};
use bitcoin::hashes::serde_macros::serde_details::SerdeHash;
use bitcoin::Block;
impl<K, V> TxIndex<K, V>
@ -246,10 +258,7 @@ mod tests {
let height = 10;
let mut chain = Blockchain::default().with_height(height as usize);
let last_six_blocks = get_last_n_blocks(&mut chain, 6).await;
let blocks: Vec<Block> = last_six_blocks
.iter()
.map(|block| block.deref().clone())
.collect();
let blocks: Vec<Block> = get_full_blocks(&last_six_blocks);
let cache: TxIndex<Locator, Transaction> = TxIndex::new(&last_six_blocks, height);
assert_eq!(blocks.len(), cache.size);
@ -258,7 +267,7 @@ mod tests {
let mut locators = Vec::new();
for tx in block.txdata.iter() {
let locator = Locator::new(tx.txid());
let locator = Locator::new(tx.compute_txid());
assert!(cache.contains_key(&locator));
locators.push(locator);
}
@ -275,19 +284,22 @@ mod tests {
let last_n_blocks = get_last_n_blocks(&mut chain, cache_size).await;
// last_n_blocks is ordered from latest to earliest
let first_block = last_n_blocks.get(cache_size - 1).unwrap();
let last_block = last_n_blocks.first().unwrap();
let mid = last_n_blocks.get(cache_size / 2).unwrap();
let first_block = get_full_block(last_n_blocks.get(cache_size - 1).unwrap());
let last_block = get_full_block(last_n_blocks.first().unwrap());
let mid_block = get_full_block(last_n_blocks.get(cache_size / 2).unwrap());
let cache: TxIndex<Locator, Transaction> = TxIndex::new(&last_n_blocks, height as u32);
assert_eq!(
cache.get_height(&first_block.block_hash()).unwrap(),
cache.get_height(&first_block.header.block_hash()).unwrap(),
height - cache_size + 1
);
assert_eq!(cache.get_height(&last_block.block_hash()).unwrap(), height);
assert_eq!(
cache.get_height(&mid.block_hash()).unwrap(),
cache.get_height(&last_block.header.block_hash()).unwrap(),
height
);
assert_eq!(
cache.get_height(&mid_block.header.block_hash()).unwrap(),
height - cache_size / 2
);
}
@ -302,8 +314,8 @@ mod tests {
height as u32,
);
let fake_hash = BlockHash::default();
assert!(cache.get_height(&fake_hash).is_none());
let fake_hash = &BlockHash::from_slice_delegated(&[0; 32]).unwrap();
assert!(cache.get_height(fake_hash).is_none());
}
#[tokio::test]
@ -315,36 +327,42 @@ mod tests {
// Store the last block to use it for an update and the first to check eviction
// Notice that the list of blocks is ordered from last to first.
let last_block = last_n_blocks.remove(0);
let first_block = last_n_blocks.last().unwrap().deref().clone();
let first_block = last_n_blocks.last().unwrap();
// Init the cache with the 6 block before the last
let mut cache = TxIndex::new(&last_n_blocks, height);
// Update the cache with the last block
let locator_tx_map = last_block
let full_block = get_full_block(&last_block);
let locator_tx_map = full_block
.txdata
.iter()
.map(|tx| (Locator::new(tx.txid()), tx.clone()))
.map(|tx| (Locator::new(tx.compute_txid()), tx.clone()))
.collect();
cache.update(last_block.deref().header, &locator_tx_map);
let header = full_block.header;
cache.update(header, &locator_tx_map);
// Check that the new data is in the cache
assert!(cache.blocks().contains(&last_block.block_hash()));
assert!(cache.blocks().contains(&header.block_hash()));
for (locator, _) in locator_tx_map.iter() {
assert!(cache.contains_key(locator));
}
let block_hash = full_block.header.block_hash();
assert_eq!(
cache.tx_in_block[&last_block.block_hash()],
cache.tx_in_block[&block_hash],
locator_tx_map.keys().cloned().collect::<Vec<Locator>>()
);
// Check that the data from the first block has been evicted
assert!(!cache.blocks().contains(&first_block.block_hash()));
for tx in first_block.txdata.iter() {
assert!(!cache.contains_key(&Locator::new(tx.txid())));
}
assert!(!cache.tx_in_block.contains_key(&first_block.block_hash()));
let first_full_block = get_full_block(first_block);
let tx = first_full_block.txdata[0].clone();
assert!(!cache.contains_key(&Locator::new(tx.compute_txid())));
let block_hash = first_full_block.header.block_hash();
assert!(!cache.tx_in_block.contains_key(&block_hash));
}
#[tokio::test]

View file

@ -4,8 +4,9 @@ use std::collections::HashMap;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Arc, Mutex};
use bitcoin::block::Header;
use bitcoin::secp256k1::SecretKey;
use bitcoin::{BlockHeader, Transaction};
use bitcoin::Transaction;
use lightning::chain;
use lightning_block_sync::poll::ValidatedBlock;
@ -261,7 +262,7 @@ impl Watcher {
"Trigger for locator {} found in cache",
appointment.locator()
);
match cryptography::decrypt(appointment.encrypted_blob(), &dispute_tx.txid()) {
match cryptography::decrypt(appointment.encrypted_blob(), &dispute_tx.compute_txid()) {
Ok(penalty_tx) => {
// Data needs to be added the database straightaway since appointments are
// FKs to trackers. If handle breach fails, data will be deleted later.
@ -383,7 +384,10 @@ impl Watcher {
let uuids = self.dbm.lock().unwrap().load_uuids(locator);
for uuid in uuids {
let appointment = self.dbm.lock().unwrap().load_appointment(uuid).unwrap();
match cryptography::decrypt(appointment.encrypted_blob(), &dispute_tx.txid()) {
match cryptography::decrypt(
appointment.encrypted_blob(),
&dispute_tx.compute_txid(),
) {
Ok(penalty_tx) => {
if let ConfirmationStatus::Rejected(_) = self.responder.handle_breach(
uuid,
@ -493,7 +497,7 @@ impl chain::Listen for Watcher {
/// told by the [Gatekeeper].
fn filtered_block_connected(
&self,
header: &BlockHeader,
header: &Header,
txdata: &chain::transaction::TransactionData,
height: u32,
) {
@ -501,7 +505,7 @@ impl chain::Listen for Watcher {
let locator_tx_map = txdata
.iter()
.map(|(_, tx)| (Locator::new(tx.txid()), (*tx).clone()))
.map(|(_, tx)| (Locator::new(tx.compute_txid()), (*tx).clone()))
.collect();
self.locator_cache
@ -522,7 +526,7 @@ impl chain::Listen for Watcher {
/// Handle reorgs in the [Watcher].
///
/// Fixes the [LocatorCache] by removing the disconnected data and updates the last_known_block_height.
fn block_disconnected(&self, header: &BlockHeader, height: u32) {
fn block_disconnected(&self, header: &Header, height: u32) {
log::warn!("Block disconnected: {}", header.block_hash());
self.locator_cache
.lock()
@ -640,7 +644,7 @@ mod tests {
// (as if simulating a bootstrap from existing data), the data should be properly loaded.
for _ in 0..10 {
let appointment = generate_dummy_appointment(None).inner;
let user_sig = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let user_sig = cryptography::sign(&appointment.to_vec(), &user_sk);
watcher
.add_appointment(appointment.clone(), user_sig.clone())
.unwrap();
@ -702,7 +706,7 @@ mod tests {
let user_id = UserId(user_pk);
watcher.register(user_id).unwrap();
let appointment = generate_dummy_appointment(None).inner;
let user_sig = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let user_sig = cryptography::sign(&appointment.to_vec(), &user_sk);
// Add the appointment for a new user (twice so we can check that updates work)
for _ in 0..2 {
@ -718,7 +722,7 @@ mod tests {
let user2_id = UserId(user2_pk);
watcher.register(user2_id).unwrap();
let user2_sig = cryptography::sign(&appointment.to_vec(), &user2_sk).unwrap();
let user2_sig = cryptography::sign(&appointment.to_vec(), &user2_sk);
let (receipt, slots, expiry) = watcher
.add_appointment(appointment.clone(), user2_sig.clone())
.unwrap();
@ -732,9 +736,8 @@ mod tests {
// If an appointment is already in the Responder, it should bounce
let dispute_tx = get_random_tx();
let (uuid, triggered_appointment) =
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.txid()));
let signature =
cryptography::sign(&triggered_appointment.inner.to_vec(), &user_sk).unwrap();
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.compute_txid()));
let signature = cryptography::sign(&triggered_appointment.inner.to_vec(), &user_sk);
let (receipt, slots, expiry) = watcher
.add_appointment(triggered_appointment.inner.clone(), signature.clone())
.unwrap();
@ -762,8 +765,8 @@ mod tests {
// If the trigger is already in the cache, the appointment will go straight to the Responder
let dispute_tx = tip_txs.last().unwrap();
let (uuid, appointment_in_cache) =
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.txid()));
let user_sig = cryptography::sign(&appointment_in_cache.inner.to_vec(), &user_sk).unwrap();
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.compute_txid()));
let user_sig = cryptography::sign(&appointment_in_cache.inner.to_vec(), &user_sk);
let (receipt, slots, expiry) = watcher
.add_appointment(appointment_in_cache.inner, user_sig.clone())
.unwrap();
@ -779,9 +782,9 @@ mod tests {
// Wrong penalty
let dispute_tx = &tip_txs[tip_txs.len() - 2];
let (uuid, mut invalid_appointment) =
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.txid()));
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.compute_txid()));
invalid_appointment.inner.encrypted_blob.reverse();
let user_sig = cryptography::sign(&invalid_appointment.inner.to_vec(), &user_sk).unwrap();
let user_sig = cryptography::sign(&invalid_appointment.inner.to_vec(), &user_sk);
let (receipt, slots, expiry) = watcher
.add_appointment(invalid_appointment.inner, user_sig.clone())
.unwrap();
@ -803,8 +806,8 @@ mod tests {
let dispute_tx = &tip_txs[tip_txs.len() - 2];
let (uuid, invalid_appointment) =
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.txid()));
let user_sig = cryptography::sign(&invalid_appointment.inner.to_vec(), &user_sk).unwrap();
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.compute_txid()));
let user_sig = cryptography::sign(&invalid_appointment.inner.to_vec(), &user_sk);
let (receipt, slots, expiry) = watcher
.add_appointment(invalid_appointment.inner, user_sig.clone())
.unwrap();
@ -841,7 +844,7 @@ mod tests {
.available_slots = 0;
let (uuid, appointment) = generate_dummy_appointment_with_user(user_id, None);
let signature = cryptography::sign(&appointment.inner.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.inner.to_vec(), &user_sk);
assert!(matches!(
watcher.add_appointment(appointment.inner, signature),
@ -856,7 +859,7 @@ mod tests {
.add_outdated_user(user2_id, START_HEIGHT as u32);
let (uuid, appointment) = generate_dummy_appointment_with_user(user2_id, None);
let signature = cryptography::sign(&appointment.inner.to_vec(), &user2_sk).unwrap();
let signature = cryptography::sign(&appointment.inner.to_vec(), &user2_sk);
assert!(matches!(
watcher.add_appointment(appointment.inner, signature),
@ -875,7 +878,7 @@ mod tests {
let (_, user_pk) = get_random_keypair();
let user_id = UserId(user_pk);
watcher.register(user_id).unwrap();
let dispute_txid = get_random_tx().txid();
let dispute_txid = get_random_tx().compute_txid();
let (uuid, appointment) =
generate_dummy_appointment_with_user(user_id, Some(&dispute_txid));
@ -917,7 +920,7 @@ mod tests {
let dispute_tx = get_random_tx();
let (uuid, appointment) =
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.txid()));
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.compute_txid()));
// Valid triggered appointments should be accepted by the Responder
assert_eq!(
@ -937,7 +940,7 @@ mod tests {
*watcher.responder.get_carrier().lock().unwrap() = carrier;
let dispute_tx = get_random_tx();
let (uuid, appointment) =
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.txid()));
generate_dummy_appointment_with_user(user_id, Some(&dispute_tx.compute_txid()));
assert_eq!(
watcher.store_triggered_appointment(uuid, &appointment, user_id, &dispute_tx),
TriggeredAppointment::Rejected,
@ -965,7 +968,7 @@ mod tests {
let (watcher, _s) = init_watcher(&mut chain).await;
let dispute_tx = get_random_tx();
let appointment = generate_dummy_appointment(Some(&dispute_tx.txid())).inner;
let appointment = generate_dummy_appointment(Some(&dispute_tx.compute_txid())).inner;
// If the user cannot be properly identified, the request will fail. This can be simulated by providing a wrong signature
let wrong_sig = String::from_utf8((0..65).collect()).unwrap();
@ -981,12 +984,12 @@ mod tests {
watcher
.add_appointment(
appointment.clone(),
cryptography::sign(&appointment.to_vec(), &user_sk).unwrap(),
cryptography::sign(&appointment.to_vec(), &user_sk),
)
.unwrap();
let message = format!("get appointment {}", appointment.locator);
let signature = cryptography::sign(message.as_bytes(), &user_sk).unwrap();
let signature = cryptography::sign(message.as_bytes(), &user_sk);
let info = watcher
.get_appointment(appointment.locator, &signature)
.unwrap();
@ -1012,7 +1015,7 @@ mod tests {
let tracker = TransactionTracker::new(breach, user_id, status);
let tracker_message = format!("get appointment {}", appointment.locator);
let tracker_signature = cryptography::sign(tracker_message.as_bytes(), &user_sk).unwrap();
let tracker_signature = cryptography::sign(tracker_message.as_bytes(), &user_sk);
let info = watcher
.get_appointment(appointment.locator, &tracker_signature)
.unwrap();
@ -1030,7 +1033,7 @@ mod tests {
let user2_id = UserId(user2_pk);
watcher.register(user2_id).unwrap();
let signature2 = cryptography::sign(message.as_bytes(), &user2_sk).unwrap();
let signature2 = cryptography::sign(message.as_bytes(), &user2_sk);
assert!(matches!(
watcher.get_appointment(appointment.locator, &signature2),
Err(GetAppointmentFailure::NotFound { .. })
@ -1055,7 +1058,7 @@ mod tests {
// Let's create some locators based on the transactions in the last block
let locator_tx_map: HashMap<_, _> = (0..10)
.map(|_| get_random_tx())
.map(|tx| (Locator::new(tx.txid()), tx))
.map(|tx| (Locator::new(tx.compute_txid()), tx))
.collect();
let (user_sk, user_pk) = get_random_keypair();
@ -1067,8 +1070,8 @@ mod tests {
for (i, (l, tx)) in locator_tx_map.iter().enumerate() {
// Track some of the these transactions.
if i % 2 == 0 {
let appointment = generate_dummy_appointment(Some(&tx.txid())).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let appointment = generate_dummy_appointment(Some(&tx.compute_txid())).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
watcher.add_appointment(appointment, signature).unwrap();
breaches.insert(*l, tx.clone());
}
@ -1086,7 +1089,7 @@ mod tests {
// Let's create some locators based on the transactions in the last block
let breaches: HashMap<_, _> = (0..10)
.map(|_| get_random_tx())
.map(|tx| (Locator::new(tx.txid()), tx))
.map(|tx| (Locator::new(tx.compute_txid()), tx))
.collect();
let (user_sk, user_pk) = get_random_keypair();
@ -1095,8 +1098,8 @@ mod tests {
// Let the watcher track these breaches.
for (_, tx) in breaches.iter() {
let appointment = generate_dummy_appointment(Some(&tx.txid())).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let appointment = generate_dummy_appointment(Some(&tx.compute_txid())).inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
watcher.add_appointment(appointment, signature).unwrap();
}
@ -1111,7 +1114,7 @@ mod tests {
// Let's create some locators based on the transactions in the last block
let breaches: HashMap<_, _> = (0..10)
.map(|_| get_random_tx())
.map(|tx| (Locator::new(tx.txid()), tx))
.map(|tx| (Locator::new(tx.compute_txid()), tx))
.collect();
let (user_sk, user_pk) = get_random_keypair();
@ -1122,14 +1125,14 @@ mod tests {
// Let the watcher track these breaches.
for (i, (_, tx)) in breaches.iter().enumerate() {
let (uuid, appointment) =
generate_dummy_appointment_with_user(user_id, Some(&tx.txid()));
generate_dummy_appointment_with_user(user_id, Some(&tx.compute_txid()));
let mut appointment = appointment.inner;
if i % 2 == 0 {
// Mal-format some appointments
appointment.encrypted_blob.reverse();
rejected.insert(uuid);
};
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
watcher.add_appointment(appointment, signature).unwrap();
}
@ -1154,7 +1157,7 @@ mod tests {
// Let's create some locators based on the transactions in the last block
let breaches: HashMap<_, _> = (0..10)
.map(|_| get_random_tx())
.map(|tx| (Locator::new(tx.txid()), tx))
.map(|tx| (Locator::new(tx.compute_txid()), tx))
.collect();
let (user_sk, user_pk) = get_random_keypair();
@ -1165,9 +1168,9 @@ mod tests {
// Let the watcher track these breaches.
for tx in breaches.values() {
let (uuid, appointment) =
generate_dummy_appointment_with_user(user_id, Some(&tx.txid()));
generate_dummy_appointment_with_user(user_id, Some(&tx.compute_txid()));
let appointment = appointment.inner;
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
watcher.add_appointment(appointment, signature).unwrap();
uuids.insert(uuid);
}
@ -1186,7 +1189,7 @@ mod tests {
// Let's create some locators based on the transactions in the last block
let breaches: HashMap<_, _> = (0..10)
.map(|_| get_random_tx())
.map(|tx| (Locator::new(tx.txid()), tx))
.map(|tx| (Locator::new(tx.compute_txid()), tx))
.collect();
let (user_sk, user_pk) = get_random_keypair();
@ -1197,14 +1200,14 @@ mod tests {
// Let the watcher track these breaches.
for (i, (_, tx)) in breaches.iter().enumerate() {
let (uuid, appointment) =
generate_dummy_appointment_with_user(user_id, Some(&tx.txid()));
generate_dummy_appointment_with_user(user_id, Some(&tx.compute_txid()));
let mut appointment = appointment.inner;
if i % 2 == 0 {
// Mal-format some appointments, they should be returned as rejected.
appointment.encrypted_blob.reverse();
rejected_breaches.insert(uuid);
};
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let signature = cryptography::sign(&appointment.to_vec(), &user_sk);
watcher.add_appointment(appointment, signature).unwrap();
}
@ -1255,11 +1258,11 @@ mod tests {
let uuid1 = UUID::new(appointment.locator, user_id);
let uuid2 = UUID::new(appointment.locator, user2_id);
let user_sig = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
let user_sig = cryptography::sign(&appointment.to_vec(), &user_sk);
watcher
.add_appointment(appointment.clone(), user_sig)
.unwrap();
let user2_sig = cryptography::sign(&appointment.to_vec(), &user2_sk).unwrap();
let user2_sig = cryptography::sign(&appointment.to_vec(), &user2_sk);
watcher.add_appointment(appointment, user2_sig).unwrap();
// Outdate the first user's registration.
@ -1298,8 +1301,8 @@ mod tests {
// Check triggers. Add a new appointment and trigger it with valid data.
let dispute_tx = get_random_tx();
let (uuid, appointment) =
generate_dummy_appointment_with_user(user2_id, Some(&dispute_tx.txid()));
let sig = cryptography::sign(&appointment.inner.to_vec(), &user2_sk).unwrap();
generate_dummy_appointment_with_user(user2_id, Some(&dispute_tx.compute_txid()));
let sig = cryptography::sign(&appointment.inner.to_vec(), &user2_sk);
watcher.add_appointment(appointment.inner, sig).unwrap();
assert!(watcher.dbm.lock().unwrap().appointment_exists(uuid));
@ -1316,10 +1319,10 @@ mod tests {
// Checks invalid triggers. Add a new appointment and trigger it with invalid data.
let dispute_tx = get_random_tx();
let (uuid, mut appointment) =
generate_dummy_appointment_with_user(user2_id, Some(&dispute_tx.txid()));
generate_dummy_appointment_with_user(user2_id, Some(&dispute_tx.compute_txid()));
// Modify the encrypted blob so the data is invalid.
appointment.inner.encrypted_blob.reverse();
let sig = cryptography::sign(&appointment.inner.to_vec(), &user2_sk).unwrap();
let sig = cryptography::sign(&appointment.inner.to_vec(), &user2_sk);
watcher.add_appointment(appointment.inner, sig).unwrap();
let block = chain.generate(Some(vec![dispute_tx]));
@ -1335,8 +1338,8 @@ mod tests {
// Check triggering with a valid formatted transaction but that is rejected by the Responder.
let dispute_tx = get_random_tx();
let (uuid, appointment) =
generate_dummy_appointment_with_user(user2_id, Some(&dispute_tx.txid()));
let sig = cryptography::sign(&appointment.inner.to_vec(), &user2_sk).unwrap();
generate_dummy_appointment_with_user(user2_id, Some(&dispute_tx.compute_txid()));
let sig = cryptography::sign(&appointment.inner.to_vec(), &user2_sk);
watcher.add_appointment(appointment.inner, sig).unwrap();
// Set the carrier response

View file

@ -25,12 +25,12 @@ tonic = { version = "0.11", features = [ "tls", "transport" ] }
tokio = { version = "1.5", features = [ "rt-multi-thread", "fs" ] }
# Bitcoin and Lightning
bitcoin = "0.28.0"
cln-plugin = "0.1.2"
bitcoin = "0.32.0"
cln-plugin = "0.3.0"
# Local
teos-common = { path = "../teos-common" }
[dev-dependencies]
mockito = "0.32.4"
tempdir = "0.3.7"
tempdir = "0.3.7"

View file

@ -8,7 +8,8 @@ use serde_json::json;
use tokio::io::{stdin, stdout};
use tokio::sync::mpsc::unbounded_channel;
use cln_plugin::options::{ConfigOption, Value};
use cln_plugin::options::config_type::DefaultInteger;
use cln_plugin::options::ConfigOption;
use cln_plugin::{anyhow, Builder, Error, Plugin};
use teos_common::appointment::{Appointment, Locator};
@ -28,6 +29,31 @@ use watchtower_plugin::retrier::RetryManager;
use watchtower_plugin::wt_client::{RevocationData, WTClient};
use watchtower_plugin::{constants, TowerStatus};
const DEV_WT_MAX_RETRY_INTERVAL_CONFIG: ConfigOption<DefaultInteger> =
ConfigOption::new_i64_with_default(
constants::DEV_WT_MAX_RETRY_INTERVAL,
constants::DEFAULT_DEV_WT_MAX_RETRY_INTERVAL,
constants::DEV_WT_MAX_RETRY_INTERVAL_DESC,
);
const WT_AUTO_RETRY_DELAY_CONFIG: ConfigOption<DefaultInteger> = ConfigOption::new_i64_with_default(
constants::WT_AUTO_RETRY_DELAY,
constants::DEFAULT_WT_AUTO_RETRY_DELAY,
constants::WT_AUTO_RETRY_DELAY_DESC,
);
const WT_MAX_RETRY_TIME_CONFIG: ConfigOption<DefaultInteger> = ConfigOption::new_i64_with_default(
constants::WT_MAX_RETRY_TIME,
constants::DEFAULT_WT_MAX_RETRY_TIME,
constants::WT_MAX_RETRY_TIME_DESC,
);
const WT_PORT_CONFG: ConfigOption<DefaultInteger> = ConfigOption::new_i64_with_default(
constants::WT_PORT,
constants::DEFAULT_WT_PORT,
constants::WT_PORT_DESC,
);
fn to_cln_error(e: RequestError) -> Error {
let e = match e {
RequestError::ConnectionError(e) => anyhow!(e),
@ -76,7 +102,7 @@ async fn register(
// which is not available in the current version of `cln-plugin` (but already on master). Add it for the next release.
let port = params.port.unwrap_or(
u16::try_from(plugin.option(constants::WT_PORT).unwrap().as_i64().unwrap())
u16::try_from(plugin.option(&WT_PORT_CONFG).unwrap())
.map_err(|_| anyhow!("{} out of range", constants::WT_PORT))?,
);
@ -162,7 +188,7 @@ async fn get_subscription_info(
}
}?;
let signature = cryptography::sign("get subscription info".as_bytes(), &user_sk).unwrap();
let signature = cryptography::sign("get subscription info".as_bytes(), &user_sk);
let response: common_msgs::GetSubscriptionInfoResponse = process_post_response(
post_request(
@ -207,8 +233,7 @@ async fn get_appointment(
let signature = cryptography::sign(
format!("get appointment {}", params.locator).as_bytes(),
&user_sk,
)
.unwrap();
);
let response: ApiResponse<common_msgs::GetAppointmentResponse> = process_post_response(
post_request(
@ -422,8 +447,7 @@ async fn on_commitment_revocation(
let signature = cryptography::sign(
&appointment.to_vec(),
&plugin.state().lock().unwrap().user_sk,
)
.unwrap();
);
// Looks like we cannot iterate through towers given a locked state is not Send (due to the async call),
// so we need to clone the bare minimum.
@ -534,26 +558,10 @@ async fn main() -> Result<(), Error> {
};
let builder = Builder::new(stdin(), stdout())
.option(ConfigOption::new(
constants::WT_PORT,
Value::Integer(constants::DEFAULT_WT_PORT),
constants::WT_PORT_DESC,
))
.option(ConfigOption::new(
constants::WT_MAX_RETRY_TIME,
Value::Integer(constants::DEFAULT_WT_MAX_RETRY_TIME),
constants::WT_MAX_RETRY_TIME_DESC,
))
.option(ConfigOption::new(
constants::WT_AUTO_RETRY_DELAY,
Value::Integer(constants::DEFAULT_WT_AUTO_RETRY_DELAY),
constants::WT_AUTO_RETRY_DELAY_DESC,
))
.option(ConfigOption::new(
constants::DEV_WT_MAX_RETRY_INTERVAL,
Value::Integer(constants::DEFAULT_DEV_WT_MAX_RETRY_INTERVAL),
constants::DEV_WT_MAX_RETRY_INTERVAL_DESC,
))
.option(WT_PORT_CONFG)
.option(WT_MAX_RETRY_TIME_CONFIG)
.option(WT_AUTO_RETRY_DELAY_CONFIG)
.option(DEV_WT_MAX_RETRY_INTERVAL_CONFIG)
.rpcmethod(
constants::RPC_REGISTER_TOWER,
constants::RPC_REGISTER_TOWER_DESC,
@ -629,34 +637,18 @@ async fn main() -> Result<(), Error> {
.await,
));
let max_elapsed_time = u16::try_from(
midstate
.option(constants::WT_MAX_RETRY_TIME)
.unwrap()
.as_i64()
.unwrap(),
)
.inspect_err(|_| {
log::error!("{} out of range", constants::WT_MAX_RETRY_TIME);
})?;
let max_elapsed_time = u16::try_from(midstate.option(&WT_MAX_RETRY_TIME_CONFIG).unwrap())
.inspect_err(|_| {
log::error!("{} out of range", constants::WT_MAX_RETRY_TIME);
})?;
let auto_retry_delay = u32::try_from(
midstate
.option(constants::WT_AUTO_RETRY_DELAY)
.unwrap()
.as_i64()
.unwrap(),
)
.inspect_err(|_| {
log::error!("{} out of range", constants::WT_AUTO_RETRY_DELAY);
})?;
let auto_retry_delay = u32::try_from(midstate.option(&WT_AUTO_RETRY_DELAY_CONFIG).unwrap())
.inspect_err(|_| {
log::error!("{} out of range", constants::WT_AUTO_RETRY_DELAY);
})?;
let max_interval_time = u16::try_from(
midstate
.option(constants::DEV_WT_MAX_RETRY_INTERVAL)
.unwrap()
.as_i64()
.unwrap(),
midstate.option(&DEV_WT_MAX_RETRY_INTERVAL_CONFIG).unwrap(),
)
.inspect_err(|_| {
log::error!("{} out of range", constants::DEV_WT_MAX_RETRY_INTERVAL);

View file

@ -491,7 +491,7 @@ impl Retrier {
&net_addr,
&proxy,
&appointment,
&cryptography::sign(&appointment.to_vec(), &user_sk).unwrap(),
&cryptography::sign(&appointment.to_vec(), &user_sk),
)
.await
{
@ -652,7 +652,7 @@ mod tests {
// Prepare the mock response
let mut add_appointment_receipt = AppointmentReceipt::new(
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk).unwrap(),
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk),
42,
);
add_appointment_receipt.sign(&tower_sk);
@ -793,7 +793,7 @@ mod tests {
// Prepare the mock response
let mut server = mockito::Server::new_async().await;
let mut add_appointment_receipt = AppointmentReceipt::new(
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk).unwrap(),
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk),
42,
);
add_appointment_receipt.sign(&tower_sk);
@ -974,7 +974,7 @@ mod tests {
// Prepare the mock response
let mut add_appointment_receipt = AppointmentReceipt::new(
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk).unwrap(),
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk),
42,
);
// Sign with a random key so it counts as misbehaving
@ -1113,7 +1113,7 @@ mod tests {
re_registration_receipt.sign(&tower_sk);
let mut add_appointment_receipt = AppointmentReceipt::new(
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk).unwrap(),
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk),
42,
);
add_appointment_receipt.sign(&tower_sk);
@ -1239,9 +1239,15 @@ mod tests {
MAX_ELAPSED_TIME as f64 + MAX_RUN_TIME,
))
.await;
let state = wt_client.lock().unwrap();
assert!(state.get_retrier_status(&tower_id).unwrap().is_idle());
wait_until!(wt_client
.lock()
.unwrap()
.get_retrier_status(&tower_id)
.unwrap()
.is_idle());
let state = wt_client.lock().unwrap();
let tower = state.towers.get(&tower_id).unwrap();
assert!(tower.pending_appointments.contains(&appointment.locator));
assert_eq!(tower.status, TowerStatus::Unreachable);
@ -1267,11 +1273,11 @@ mod tests {
// Create the receipts, the responses and set the mocks
let mut appointment_receipt = AppointmentReceipt::new(
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk).unwrap(),
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk),
42,
);
let mut appointment2_receipt = AppointmentReceipt::new(
cryptography::sign(&appointment2.to_vec(), &wt_client.lock().unwrap().user_sk).unwrap(),
cryptography::sign(&appointment2.to_vec(), &wt_client.lock().unwrap().user_sk),
42,
);
appointment_receipt.sign(&tower_sk);
@ -1368,7 +1374,7 @@ mod tests {
// Prepare the mock response
let mut add_appointment_receipt = AppointmentReceipt::new(
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk).unwrap(),
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk),
42,
);
add_appointment_receipt.sign(&tower_sk);
@ -1439,7 +1445,7 @@ mod tests {
// Prepare the mock response
let mut add_appointment_receipt = AppointmentReceipt::new(
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk).unwrap(),
cryptography::sign(&appointment.to_vec(), &wt_client.lock().unwrap().user_sk),
42,
);
add_appointment_receipt.sign(&cryptography::get_random_keypair().0);