Skip to content
This repository was archived by the owner on Mar 23, 2021. It is now read-only.

Commit a4c7f7f

Browse files
author
Tobin C. Harding
committed
Add timestamp to db accepted swaps
Add a column to the two accepted swap tables. Use SQLite auto-generation of timestamp to populate this column when an accepted swap is stored in the database. Add and test a database function to retrieve the timestamp for an [accepted] swap id.
1 parent ad418ac commit a4c7f7f

File tree

10 files changed

+188
-11
lines changed

10 files changed

+188
-11
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cnd/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ config = { version = "0.9", features = ["toml"] }
1919
debug_stub_derive = "0.3"
2020
derivative = "1"
2121
derive_more = "0.99.2"
22-
diesel = { version = "1.4", features = ["sqlite"] }
22+
diesel = { version = "1.4", features = ["sqlite", "chrono"] }
2323
diesel_migrations = "1.4.0"
2424
directories = "2.0"
2525
either = "1.5"

cnd/migrations/2019-11-11-034058_create-message-tables/up.sql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,17 @@ CREATE TABLE rfc003_ethereum_bitcoin_accept_messages
7171
id INTEGER NOT NULL PRIMARY KEY,
7272
swap_id UNIQUE NOT NULL,
7373
bitcoin_refund_identity NOT NULL,
74-
ethereum_redeem_identity NOT NULL
74+
ethereum_redeem_identity NOT NULL,
75+
at DATETIME DEFAULT CURRENT_TIMESTAMP
7576
);
7677

7778
CREATE TABLE rfc003_bitcoin_ethereum_accept_messages
7879
(
7980
id INTEGER NOT NULL PRIMARY KEY,
8081
swap_id UNIQUE NOT NULL,
8182
bitcoin_redeem_identity NOT NULL,
82-
ethereum_refund_identity NOT NULL
83+
ethereum_refund_identity NOT NULL,
84+
at DATETIME DEFAULT CURRENT_TIMESTAMP
8385
);
8486

8587
CREATE TABLE rfc003_decline_messages

cnd/src/db/integration_tests.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,17 @@ macro_rules! db_roundtrip_test {
5454
db.save(saved_accept.clone()).await?;
5555

5656
let loaded_swap = Retrieve::get(&db, &swap_id).await?;
57-
let (loaded_request, loaded_accept) = db.load_accepted_swap(&swap_id).await?;
57+
let (loaded_request, loaded_accept, _at) = db.load_accepted_swap(&swap_id).await?;
5858
let loaded_swap_types = db.determine_types(&swap_id).await?;
5959

6060
Ok((loaded_swap, loaded_request, loaded_accept, loaded_swap_types))
6161
})?;
6262

6363
Ok(
6464
saved_request == loaded_request &&
65-
saved_accept == loaded_accept &&
66-
loaded_swap == saved_swap &&
67-
loaded_swap_types == expected_swap_types
65+
saved_accept == loaded_accept &&
66+
saved_swap == loaded_swap &&
67+
expected_swap_types == loaded_swap_types
6868
)
6969
}
7070

cnd/src/db/load_swaps.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ use crate::{
1717
timestamp::Timestamp,
1818
};
1919
use async_trait::async_trait;
20+
use chrono::NaiveDateTime;
2021
use diesel::{self, prelude::*, RunQueryDsl};
2122

22-
pub type AcceptedSwap<AL, BL, AA, BA> = (Request<AL, BL, AA, BA>, Accept<AL, BL>);
23+
pub type AcceptedSwap<AL, BL, AA, BA> = (Request<AL, BL, AA, BA>, Accept<AL, BL>, NaiveDateTime);
2324

2425
#[async_trait]
2526
pub trait LoadAcceptedSwap<AL: Ledger, BL: Ledger, AA: Asset, BA: Asset> {
@@ -46,6 +47,8 @@ struct BitcoinEthereumBitcoinEtherAcceptedSwap {
4647
// Accept fields.
4748
bitcoin_redeem_identity: Text<bitcoin::PublicKey>,
4849
ethereum_refund_identity: Text<EthereumAddress>,
50+
51+
at: NaiveDateTime,
4952
}
5053

5154
#[async_trait]
@@ -86,6 +89,7 @@ impl LoadAcceptedSwap<Bitcoin, Ethereum, bitcoin::Amount, EtherQuantity> for Sql
8689
request_messages::secret_hash,
8790
accept_messages::bitcoin_redeem_identity,
8891
accept_messages::ethereum_refund_identity,
92+
accept_messages::at,
8993
))
9094
.filter(accept_messages::swap_id.eq(key))
9195
.first(connection)
@@ -119,6 +123,7 @@ impl LoadAcceptedSwap<Bitcoin, Ethereum, bitcoin::Amount, EtherQuantity> for Sql
119123
),
120124
beta_ledger_refund_identity: (record.ethereum_refund_identity.0).0,
121125
},
126+
record.at,
122127
))
123128
}
124129
}
@@ -140,6 +145,8 @@ struct EthereumBitcoinEtherBitcoinAcceptedSwap {
140145
// Accept fields.
141146
ethereum_redeem_identity: Text<EthereumAddress>,
142147
bitcoin_refund_identity: Text<bitcoin::PublicKey>,
148+
149+
at: NaiveDateTime,
143150
}
144151

145152
#[async_trait]
@@ -178,6 +185,7 @@ impl LoadAcceptedSwap<Ethereum, Bitcoin, EtherQuantity, bitcoin::Amount> for Sql
178185
request_messages::secret_hash,
179186
accept_messages::ethereum_redeem_identity,
180187
accept_messages::bitcoin_refund_identity,
188+
accept_messages::at,
181189
))
182190
.filter(accept_messages::swap_id.eq(key))
183191
.first(connection)
@@ -211,6 +219,7 @@ impl LoadAcceptedSwap<Ethereum, Bitcoin, EtherQuantity, bitcoin::Amount> for Sql
211219
*record.bitcoin_refund_identity,
212220
),
213221
},
222+
record.at,
214223
))
215224
}
216225
}
@@ -233,6 +242,8 @@ struct BitcoinEthereumBitcoinErc20AcceptedSwap {
233242
// Accept fields.
234243
bitcoin_redeem_identity: Text<bitcoin::PublicKey>,
235244
ethereum_refund_identity: Text<EthereumAddress>,
245+
246+
at: NaiveDateTime,
236247
}
237248

238249
#[async_trait]
@@ -272,6 +283,7 @@ impl LoadAcceptedSwap<Bitcoin, Ethereum, bitcoin::Amount, Erc20Token> for Sqlite
272283
request_messages::secret_hash,
273284
accept_messages::bitcoin_redeem_identity,
274285
accept_messages::ethereum_refund_identity,
286+
accept_messages::at,
275287
))
276288
.filter(accept_messages::swap_id.eq(key))
277289
.first(connection)
@@ -308,6 +320,7 @@ impl LoadAcceptedSwap<Bitcoin, Ethereum, bitcoin::Amount, Erc20Token> for Sqlite
308320
),
309321
beta_ledger_refund_identity: (record.ethereum_refund_identity.0).0,
310322
},
323+
record.at,
311324
))
312325
}
313326
}
@@ -330,6 +343,8 @@ struct EthereumBitcoinErc20BitcoinAcceptedSwap {
330343
// Accept fields.
331344
ethereum_redeem_identity: Text<EthereumAddress>,
332345
bitcoin_refund_identity: Text<bitcoin::PublicKey>,
346+
347+
at: NaiveDateTime,
333348
}
334349

335350
#[async_trait]
@@ -369,6 +384,7 @@ impl LoadAcceptedSwap<Ethereum, Bitcoin, Erc20Token, bitcoin::Amount> for Sqlite
369384
request_messages::secret_hash,
370385
accept_messages::ethereum_redeem_identity,
371386
accept_messages::bitcoin_refund_identity,
387+
accept_messages::at,
372388
))
373389
.filter(accept_messages::swap_id.eq(key))
374390
.first(connection)
@@ -405,6 +421,7 @@ impl LoadAcceptedSwap<Ethereum, Bitcoin, Erc20Token, bitcoin::Amount> for Sqlite
405421
*record.bitcoin_refund_identity,
406422
),
407423
},
424+
record.at,
408425
))
409426
}
410427
}

cnd/src/db/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl Sqlite {
8686
async fn role(&self, key: &SwapId) -> anyhow::Result<Role> {
8787
use self::schema::rfc003_swaps as swaps;
8888

89-
let record: QueryableSwap = self
89+
let record: QueryableSwapRole = self
9090
.do_in_transaction(|connection| {
9191
let key = Text(key);
9292

@@ -118,7 +118,7 @@ fn ensure_folder_tree_exists(path: &Path) -> anyhow::Result<()> {
118118
}
119119

120120
#[derive(Queryable, Debug, Clone, PartialEq)]
121-
struct QueryableSwap {
121+
struct QueryableSwapRole {
122122
pub swap_id: Text<SwapId>,
123123
pub role: Text<Role>,
124124
}

cnd/src/db/save.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ impl Save<Request<Ethereum, Bitcoin, Erc20Token, bitcoin::Amount>> for Sqlite {
317317
Ok(())
318318
}
319319
}
320+
320321
#[derive(Insertable, Debug, Copy, Clone)]
321322
#[table_name = "rfc003_ethereum_bitcoin_accept_messages"]
322323
struct InsertableEthereumBitcoinAcceptMessage {

cnd/src/db/schema.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ table! {
7474
swap_id -> Text,
7575
ethereum_redeem_identity -> Text,
7676
bitcoin_refund_identity -> Text,
77+
at -> Timestamp,
7778
}
7879
}
7980

@@ -83,6 +84,7 @@ table! {
8384
swap_id -> Text,
8485
bitcoin_redeem_identity -> Text,
8586
ethereum_refund_identity -> Text,
87+
at -> Timestamp,
8688
}
8789
}
8890

cnd/src/load_swaps.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub async fn load_swaps_from_database(
3333
db.load_accepted_swap(&swap_id).await;
3434

3535
match accepted {
36-
Ok((request, accept)) => {
36+
Ok((request, accept, _at)) => {
3737
match types.role {
3838
Role::Alice => {
3939
let state = alice::State::accepted(request.clone(), accept, seed);

cnd/tests/db.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
use bitcoin::{self, secp256k1::Secp256k1};
2+
use chrono::NaiveDateTime;
3+
use cnd::{
4+
bitcoin::PublicKey,
5+
db::{AcceptedSwap, LoadAcceptedSwap, Save, Sqlite, Swap},
6+
swap_protocols::{
7+
ledger::{Bitcoin, Ethereum},
8+
rfc003::{Accept, Request, Secret, SecretHash},
9+
HashFunction, Role, SwapId,
10+
},
11+
timestamp::Timestamp,
12+
};
13+
use ethereum_support::{Address, EtherQuantity};
14+
use futures_core::{FutureExt, TryFutureExt};
15+
use libp2p::PeerId;
16+
use std::str::FromStr;
17+
use tokio::{self, runtime::current_thread::Runtime};
18+
19+
#[test]
20+
fn accepted_swap_has_valid_timestamp() {
21+
let mut runtime = Runtime::new().expect("failed to create new runtime");
22+
23+
let future = accepted_at_for_bitcoin_ethereum();
24+
// If this assignment works then we have a valid NaiveDateTime.
25+
let _accepted_at = runtime
26+
.block_on(future.boxed().compat())
27+
.expect("failed to get accepted swap");
28+
29+
let future = accepted_at_for_ethereum_bitcoin();
30+
let _accepted_at = runtime
31+
.block_on(future.boxed().compat())
32+
.expect("failed to get accepted swap");
33+
}
34+
35+
async fn accepted_at_for_bitcoin_ethereum() -> anyhow::Result<NaiveDateTime> {
36+
let swap_id = swap_id();
37+
let role = Role::Alice;
38+
39+
let db_path = tempfile::Builder::new()
40+
.prefix(&swap_id.to_string())
41+
.suffix(".sqlite")
42+
.tempfile()
43+
.unwrap()
44+
.into_temp_path();
45+
let db = Sqlite::new(&db_path).expect("db");
46+
47+
let swap = swap(swap_id, role);
48+
db.save(swap).await?;
49+
50+
let request = Request {
51+
swap_id,
52+
alpha_ledger: Bitcoin::default(),
53+
beta_ledger: Ethereum::default(),
54+
alpha_asset: bitcoin::Amount::default(),
55+
beta_asset: EtherQuantity::zero(),
56+
hash_function: HashFunction::Sha256,
57+
alpha_ledger_refund_identity: bitcoin_address(),
58+
beta_ledger_redeem_identity: ethereum_address(),
59+
alpha_expiry: Timestamp::now(),
60+
beta_expiry: Timestamp::now(),
61+
secret_hash: secret_hash(),
62+
};
63+
db.save(request).await?;
64+
65+
let accept: Accept<Bitcoin, Ethereum> = Accept {
66+
swap_id: swap_id.clone(),
67+
beta_ledger_refund_identity: ethereum_address(), // This is non-sense but fine for this test
68+
alpha_ledger_redeem_identity: bitcoin_address(), // same address for refund/redeem.
69+
};
70+
db.save(accept).await?;
71+
72+
let accepted_swap: AcceptedSwap<Bitcoin, Ethereum, bitcoin::Amount, EtherQuantity> =
73+
db.load_accepted_swap(&swap_id).await?;
74+
75+
let (_request, _accept, at) = accepted_swap;
76+
77+
Ok(at)
78+
}
79+
80+
async fn accepted_at_for_ethereum_bitcoin() -> anyhow::Result<NaiveDateTime> {
81+
let swap_id = swap_id();
82+
let role = Role::Bob;
83+
84+
let db_path = tempfile::Builder::new()
85+
.prefix(&swap_id.to_string())
86+
.suffix(".sqlite")
87+
.tempfile()
88+
.unwrap()
89+
.into_temp_path();
90+
let db = Sqlite::new(&db_path).expect("db");
91+
92+
let swap = swap(swap_id.clone(), role);
93+
db.save(swap).await?;
94+
95+
let request = Request {
96+
swap_id: swap_id.clone(),
97+
alpha_ledger: Ethereum::default(),
98+
beta_ledger: Bitcoin::default(),
99+
alpha_asset: EtherQuantity::zero(),
100+
beta_asset: bitcoin::Amount::default(),
101+
hash_function: HashFunction::Sha256,
102+
alpha_ledger_refund_identity: ethereum_address(),
103+
beta_ledger_redeem_identity: bitcoin_address(),
104+
alpha_expiry: Timestamp::now(),
105+
beta_expiry: Timestamp::now(),
106+
secret_hash: secret_hash(),
107+
};
108+
db.save(request).await?;
109+
110+
let accept: Accept<Ethereum, Bitcoin> = Accept {
111+
swap_id: swap_id.clone(),
112+
beta_ledger_refund_identity: bitcoin_address(), // This is non-sense but fine for this test
113+
alpha_ledger_redeem_identity: ethereum_address(), // same address for refund/redeem.
114+
};
115+
db.save(accept).await?;
116+
117+
let accepted_swap: AcceptedSwap<Ethereum, Bitcoin, EtherQuantity, bitcoin::Amount> =
118+
db.load_accepted_swap(&swap_id).await?;
119+
120+
let (_request, _accept, at) = accepted_swap;
121+
122+
Ok(at)
123+
}
124+
125+
fn swap_id() -> SwapId {
126+
SwapId::from_str("0123456789abcdef0123456789abcdef").unwrap()
127+
}
128+
129+
fn swap(swap_id: SwapId, role: Role) -> Swap {
130+
Swap {
131+
swap_id,
132+
role,
133+
counterparty: PeerId::random(),
134+
}
135+
}
136+
137+
fn bitcoin_address() -> PublicKey {
138+
let s = Secp256k1::new();
139+
let sk = bitcoin::PrivateKey::from_str("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")
140+
.unwrap();
141+
let pk = bitcoin::PublicKey::from_private_key(&s, &sk);
142+
143+
PublicKey::from(pk)
144+
}
145+
146+
fn ethereum_address() -> Address {
147+
Address::from_str("0A81e8be41b21f651a71aaB1A85c6813b8bBcCf8").unwrap()
148+
}
149+
150+
fn secret_hash() -> SecretHash {
151+
let bytes = b"hello world, you are beautiful!!";
152+
let secret = Secret::from(*bytes);
153+
secret.hash()
154+
}

0 commit comments

Comments
 (0)