Skip to content

Commit 6185a28

Browse files
committed
initial checkin
0 parents  commit 6185a28

26 files changed

+8912
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/target/
2+
**/*.rs.bk
3+
Cargo.lock
4+
/target/
5+
**/*.rs.bk

Cargo.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "lightning"
3+
version = "0.0.1"
4+
authors = ["Matt Corallo"]
5+
license = "AGPL-3.0"
6+
repository = "https://github.com/TheBlueMatt/rust-lightning/"
7+
description = """
8+
A Bitcoin Lightning implementation in Rust.
9+
Still super-early code-dump quality and is missing large chunks. See README in git repo for suggested projects if you want to contribute. Don't have to bother telling you not to use this for anything serious, because you'd have to finish building it to even try.
10+
"""
11+
12+
[features]
13+
# Supports tracking channels with a non-bitcoin chain hashes. Currently enables all kinds of fun DoS attacks.
14+
non_bitcoin_chain_hash_routing = []
15+
16+
[dependencies]
17+
bitcoin = "0.10.7"
18+
rust-crypto = "0.2"
19+
rand = "0.3"
20+
secp256k1 = "0.8.1"
21+
num = "0.1"

README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
Rust-Lightning, not Rusty's Lightning!
2+
3+
Currently somewhere near 5% towards usable, published to see if there is any
4+
real interest from folks in either contributing to or using a lightning rust
5+
library.
6+
7+
The goal is to provide a full-featured but also incredibly flexible lightning
8+
implementation, allowing the user to decide how they wish to use it. With that
9+
in mind, everything should be exposed via simple, composable APIs. The user
10+
should be able to decide whether they wish to use their own threading/execution
11+
models, allowing usage inside of existing library architectures, or allow us to
12+
handle that for them. Same goes with network connections - if the user wishes
13+
to use their own networking stack, they should be able to do so! This all means
14+
that we should provide simple external interfaces which allow the user to drive
15+
all execution, while implementing sample execution drivers that create a
16+
full-featured lightning daemon by default.
17+
18+
For security reasons, do not add new dependencies. Really do not add new
19+
non-optional/non-test/non-library dependencies. Really really do not add
20+
dependencies with dependencies. Do convince Andrew to cut down dependency usage
21+
in rust-bitcoin.
22+
23+
Assorted random TODOs:
24+
25+
* Create a general timer interface - this should be passed around in reference
26+
form to most objects to allow them to register functions which are called on
27+
a timer. By default we should provide an implementation of this which uses
28+
some newfangled rusty promise-y library, but should generally ensure a
29+
client can simply integrate this into whatever existing timer interface
30+
they use.
31+
32+
* Networking...having a simple bytes-in-bytes-out interface which does message
33+
handling and calls our encryption layer is probably the right approach. We
34+
should then also probably use the same promise-y library we use for timers
35+
to do socket selection and reading/writing.
36+
37+
* Figure out how to expose when-to-connect and who-to-connect-to.
38+
39+
* Implement when-to-connect and who-to-connect-to based on route/node rumoring
40+
and channelmanager state.
41+
42+
* Some kind of serialization format for on-disk storage of things like
43+
channels, channelmonitors, routing db, etc.
44+
45+
* BOLT 10/network bootstrapping implementation.
46+
47+
* Some kind of DoS thing including ban tracking and putting that info in
48+
HandleError (and also rename HandleError) to be propagated up...and then
49+
handled.
50+
51+
* All the random TODOs and unimplemented!()s across the codebase.
52+
53+
* BOLT 11 (invoice/address creation/generation) implementation
54+
55+
* Type-ify our somewhat random usage of Uint256/[u8; 32]. Use Sha256dHash
56+
where appropriate, create our own types for everything else.
57+
58+
* Some kind of logging subsystem/API.
59+
60+
Notes on coding style:
61+
* Use tabs. If you want to align lines, use spaces. Any desired alignment
62+
should display fine at any tab-length display setting.
63+
64+
License is AGPL, but with agreement that Matt can relicense under any other
65+
OSI-approved license at will (and likely will with sufficient motivation).

src/chain/bitcoincorerpcchain.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use bitcoin::blockdata::transaction::Transaction;
2+
use bitcoin::blockdata::script::Script;
3+
use bitcoin::util::hash::Sha256dHash;
4+
5+
use chain::chaininterface::{ChainWatchInterface,ChainWatchInterfaceUtil,ChainListener};
6+
7+
use std::sync::Weak;
8+
9+
pub struct BitcoinCoreRPCClientChain {
10+
util: ChainWatchInterfaceUtil
11+
}
12+
13+
impl ChainWatchInterface for BitcoinCoreRPCClientChain {
14+
fn install_watch_script(&self, spk: Script) {
15+
self.util.install_watch_script(spk)
16+
}
17+
18+
fn install_watch_outpoint(&self, outpoint: (Sha256dHash, u32)) {
19+
self.util.install_watch_outpoint(outpoint)
20+
}
21+
22+
fn watch_all_txn(&self) {
23+
self.util.watch_all_txn()
24+
}
25+
26+
fn broadcast_transaction(&self, _tx: &Transaction) {
27+
unimplemented!()
28+
}
29+
30+
fn register_listener(&self, listener: Weak<ChainListener>) {
31+
self.util.register_listener(listener)
32+
}
33+
}
34+
35+
impl BitcoinCoreRPCClientChain {
36+
pub fn new() -> BitcoinCoreRPCClientChain {
37+
BitcoinCoreRPCClientChain {
38+
util: ChainWatchInterfaceUtil::new(),
39+
}
40+
}
41+
}

src/chain/chaininterface.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
use bitcoin::blockdata::block::BlockHeader;
2+
use bitcoin::blockdata::transaction::Transaction;
3+
use bitcoin::blockdata::script::Script;
4+
use bitcoin::util::hash::Sha256dHash;
5+
6+
use std::sync::{Weak,Mutex};
7+
8+
/// An interface to request notification of certain scripts as they appear the
9+
/// chain.
10+
pub trait ChainWatchInterface: Sync + Send {
11+
/// Provides a scriptPubKey which much be watched for.
12+
fn install_watch_script(&self, script_pub_key: Script);
13+
14+
/// Provides an outpoint which must be watched for, providing any transactions which spend the
15+
/// given outpoint.
16+
fn install_watch_outpoint(&self, outpoint: (Sha256dHash, u32));
17+
18+
/// Indicates that a listener needs to see all transactions.
19+
fn watch_all_txn(&self);
20+
21+
/// Sends a transaction out to (hopefully) be mined
22+
fn broadcast_transaction(&self, tx: &Transaction);
23+
24+
fn register_listener(&self, listener: Weak<ChainListener>);
25+
//TODO: unregister
26+
}
27+
28+
/// A trait indicating a desire to listen for events from the chain
29+
pub trait ChainListener: Sync + Send {
30+
/// Notifies a listener that a block was connected.
31+
/// Note that if a new script/transaction is watched during a block_connected call, the block
32+
/// *must* be re-scanned with the new script/transaction and block_connected should be called
33+
/// again with the same header and (at least) the new transactions.
34+
/// This also means those counting confirmations using block_connected callbacks should watch
35+
/// for duplicate headers and not count them towards confirmations!
36+
fn block_connected(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]);
37+
/// Notifies a listener that a block was disconnected.
38+
/// Unlike block_connected, this *must* never be called twice for the same disconnect event.
39+
fn block_disconnected(&self, header: &BlockHeader);
40+
}
41+
42+
pub enum ConfirmationTarget {
43+
Background,
44+
Normal,
45+
HighPriority,
46+
}
47+
48+
pub trait FeeEstimator: Sync + Send {
49+
fn get_est_sat_per_vbyte(&self, ConfirmationTarget) -> u64;
50+
}
51+
52+
/// Utility to capture some common parts of ChainWatchInterface implementors.
53+
/// Keeping a local copy of this in a ChainWatchInterface implementor is likely useful.
54+
pub struct ChainWatchInterfaceUtil {
55+
watched: Mutex<(Vec<Script>, Vec<(Sha256dHash, u32)>, bool)>, //TODO: Something clever to optimize this
56+
listeners: Mutex<Vec<Weak<ChainListener>>>,
57+
}
58+
59+
impl ChainWatchInterfaceUtil {
60+
pub fn new() -> ChainWatchInterfaceUtil {
61+
ChainWatchInterfaceUtil {
62+
watched: Mutex::new((Vec::new(), Vec::new(), false)),
63+
listeners: Mutex::new(Vec::new()),
64+
}
65+
}
66+
67+
pub fn install_watch_script(&self, spk: Script) {
68+
let mut watched = self.watched.lock().unwrap();
69+
watched.0.push(Script::from(spk));
70+
}
71+
72+
pub fn install_watch_outpoint(&self, outpoint: (Sha256dHash, u32)) {
73+
let mut watched = self.watched.lock().unwrap();
74+
watched.1.push(outpoint);
75+
}
76+
77+
pub fn watch_all_txn(&self) { //TODO: refcnt this?
78+
let mut watched = self.watched.lock().unwrap();
79+
watched.2 = true;
80+
}
81+
82+
pub fn register_listener(&self, listener: Weak<ChainListener>) {
83+
let mut vec = self.listeners.lock().unwrap();
84+
vec.push(listener);
85+
}
86+
87+
pub fn do_call_block_connected(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) {
88+
let listeners = self.listeners.lock().unwrap().clone();
89+
for listener in listeners.iter() {
90+
match listener.upgrade() {
91+
Some(arc) => arc.block_connected(header, height, txn_matched, indexes_of_txn_matched),
92+
None => ()
93+
}
94+
}
95+
}
96+
97+
pub fn do_call_block_disconnected(&self, header: &BlockHeader) {
98+
let listeners = self.listeners.lock().unwrap().clone();
99+
for listener in listeners.iter() {
100+
match listener.upgrade() {
101+
Some(arc) => arc.block_disconnected(header),
102+
None => ()
103+
}
104+
}
105+
}
106+
107+
/// Checks if a given transaction matches the current filter
108+
pub fn does_match_tx(&self, tx: &Transaction) -> bool {
109+
let watched = self.watched.lock().unwrap();
110+
if watched.2 {
111+
return true;
112+
}
113+
for out in tx.output.iter() {
114+
for script in watched.0.iter() {
115+
if script[..] == out.script_pubkey[..] {
116+
return true;
117+
}
118+
}
119+
}
120+
for input in tx.input.iter() {
121+
for outpoint in watched.1.iter() {
122+
let &(outpoint_hash, outpoint_index) = outpoint;
123+
if outpoint_hash == input.prev_hash && outpoint_index == input.prev_index {
124+
return true;
125+
}
126+
}
127+
}
128+
false
129+
}
130+
}

src/chain/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub mod chaininterface;
2+
pub mod bitcoincorerpcchain;
3+
pub mod rustbitcoinchain;

src/chain/rustbitcoinchain.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use bitcoin::blockdata::blockchain::Blockchain;
2+
use bitcoin::blockdata::transaction::Transaction;
3+
use bitcoin::blockdata::block::Block;
4+
use bitcoin::blockdata::script::Script;
5+
use bitcoin::network::constants::Network;
6+
use bitcoin::util::hash::Sha256dHash;
7+
8+
use chain::chaininterface::{ChainWatchInterface,ChainWatchInterfaceUtil,ChainListener};
9+
10+
use std::sync::{Mutex,Weak};
11+
12+
/// Implements a ChainWatchInterface using rust-bitcoin's Blockchain class
13+
pub struct ChainWatchImpl {
14+
chain: Mutex<Blockchain>,
15+
util: ChainWatchInterfaceUtil
16+
}
17+
18+
unsafe impl Send for ChainWatchImpl {} //TODO: GAH WTF
19+
unsafe impl Sync for ChainWatchImpl {} //TODO: GAH WTF
20+
21+
impl ChainWatchInterface for ChainWatchImpl {
22+
fn install_watch_script(&self, spk: Script) {
23+
self.util.install_watch_script(spk)
24+
}
25+
26+
fn install_watch_outpoint(&self, outpoint: (Sha256dHash, u32)) {
27+
self.util.install_watch_outpoint(outpoint)
28+
}
29+
30+
fn watch_all_txn(&self) {
31+
self.util.watch_all_txn()
32+
}
33+
34+
fn broadcast_transaction(&self, _tx: &Transaction) {
35+
unimplemented!()
36+
}
37+
38+
fn register_listener(&self, listener: Weak<ChainListener>) {
39+
self.util.register_listener(listener)
40+
}
41+
}
42+
43+
impl ChainWatchImpl {
44+
pub fn new(network: Network) -> ChainWatchImpl {
45+
ChainWatchImpl {
46+
chain: Mutex::new(Blockchain::new(network)),
47+
util: ChainWatchInterfaceUtil::new(),
48+
}
49+
}
50+
51+
pub fn add_block(&mut self, block: Block) {
52+
{
53+
let mut txn_matched: Vec<&Transaction> = Vec::new();
54+
let mut indexes_of_txn_matched = Vec::new();
55+
for (idx, tx) in block.txdata.iter().enumerate() {
56+
if self.util.does_match_tx(&tx) {
57+
txn_matched.push(tx);
58+
indexes_of_txn_matched.push(idx as u32);
59+
}
60+
}
61+
//TODO: Height
62+
self.util.do_call_block_connected(&block.header, 0, &txn_matched[..], &indexes_of_txn_matched[..]);
63+
}
64+
self.chain.lock().unwrap().add_block(block);
65+
}
66+
}

src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![crate_name = "lightning"]
2+
3+
extern crate bitcoin;
4+
extern crate secp256k1;
5+
extern crate rand;
6+
extern crate crypto;
7+
extern crate num; //TODO: Convince andrew to not rely on this for fucking casting...
8+
9+
pub mod chain;
10+
pub mod wallet;
11+
pub mod ln;
12+
pub mod util;

0 commit comments

Comments
 (0)