bitcoin-ruby 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +12 -0
- data/COPYING +18 -0
- data/Gemfile +4 -0
- data/README.rdoc +189 -0
- data/Rakefile +104 -0
- data/bin/bitcoin_dns_seed +130 -0
- data/bin/bitcoin_gui +80 -0
- data/bin/bitcoin_node +174 -0
- data/bin/bitcoin_shell +12 -0
- data/bin/bitcoin_wallet +323 -0
- data/bitcoin-ruby.gemspec +27 -0
- data/concept-examples/blockchain-pow.rb +151 -0
- data/doc/CONFIG.rdoc +66 -0
- data/doc/EXAMPLES.rdoc +9 -0
- data/doc/NODE.rdoc +35 -0
- data/doc/STORAGE.rdoc +21 -0
- data/doc/WALLET.rdoc +102 -0
- data/examples/balance.rb +60 -0
- data/examples/bbe_verify_tx.rb +55 -0
- data/examples/connect.rb +36 -0
- data/examples/relay_tx.rb +22 -0
- data/examples/verify_tx.rb +57 -0
- data/lib/bitcoin.rb +370 -0
- data/lib/bitcoin/builder.rb +266 -0
- data/lib/bitcoin/config.rb +56 -0
- data/lib/bitcoin/connection.rb +126 -0
- data/lib/bitcoin/ffi/openssl.rb +121 -0
- data/lib/bitcoin/gui/addr_view.rb +42 -0
- data/lib/bitcoin/gui/bitcoin-ruby.png +0 -0
- data/lib/bitcoin/gui/bitcoin-ruby.svg +80 -0
- data/lib/bitcoin/gui/conn_view.rb +36 -0
- data/lib/bitcoin/gui/connection.rb +68 -0
- data/lib/bitcoin/gui/em_gtk.rb +28 -0
- data/lib/bitcoin/gui/gui.builder +1643 -0
- data/lib/bitcoin/gui/gui.rb +290 -0
- data/lib/bitcoin/gui/helpers.rb +113 -0
- data/lib/bitcoin/gui/tree_view.rb +82 -0
- data/lib/bitcoin/gui/tx_view.rb +67 -0
- data/lib/bitcoin/key.rb +125 -0
- data/lib/bitcoin/logger.rb +65 -0
- data/lib/bitcoin/network/command_client.rb +93 -0
- data/lib/bitcoin/network/command_handler.rb +179 -0
- data/lib/bitcoin/network/connection_handler.rb +274 -0
- data/lib/bitcoin/network/node.rb +399 -0
- data/lib/bitcoin/protocol.rb +140 -0
- data/lib/bitcoin/protocol/address.rb +48 -0
- data/lib/bitcoin/protocol/alert.rb +47 -0
- data/lib/bitcoin/protocol/block.rb +154 -0
- data/lib/bitcoin/protocol/handler.rb +38 -0
- data/lib/bitcoin/protocol/parser.rb +148 -0
- data/lib/bitcoin/protocol/tx.rb +205 -0
- data/lib/bitcoin/protocol/txin.rb +97 -0
- data/lib/bitcoin/protocol/txout.rb +73 -0
- data/lib/bitcoin/protocol/version.rb +70 -0
- data/lib/bitcoin/script.rb +634 -0
- data/lib/bitcoin/storage/dummy.rb +164 -0
- data/lib/bitcoin/storage/models.rb +133 -0
- data/lib/bitcoin/storage/sequel.rb +335 -0
- data/lib/bitcoin/storage/sequel_store/sequel_migrations.rb +84 -0
- data/lib/bitcoin/storage/storage.rb +243 -0
- data/lib/bitcoin/version.rb +3 -0
- data/lib/bitcoin/wallet/coinselector.rb +30 -0
- data/lib/bitcoin/wallet/keygenerator.rb +75 -0
- data/lib/bitcoin/wallet/keystore.rb +203 -0
- data/lib/bitcoin/wallet/txdp.rb +116 -0
- data/lib/bitcoin/wallet/wallet.rb +243 -0
- data/spec/bitcoin/bitcoin_spec.rb +472 -0
- data/spec/bitcoin/builder_spec.rb +90 -0
- data/spec/bitcoin/fixtures/0d0affb5964abe804ffe85e53f1dbb9f29e406aa3046e2db04fba240e63c7fdd.json +27 -0
- data/spec/bitcoin/fixtures/23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63.json +23 -0
- data/spec/bitcoin/fixtures/477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590.json +27 -0
- data/spec/bitcoin/fixtures/60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1.json +45 -0
- data/spec/bitcoin/fixtures/bc179baab547b7d7c1d5d8d6f8b0cc6318eaa4b0dd0a093ad6ac7f5a1cb6b3ba.json +34 -0
- data/spec/bitcoin/fixtures/rawblock-0.bin +0 -0
- data/spec/bitcoin/fixtures/rawblock-0.json +39 -0
- data/spec/bitcoin/fixtures/rawblock-1.bin +0 -0
- data/spec/bitcoin/fixtures/rawblock-1.json +39 -0
- data/spec/bitcoin/fixtures/rawblock-131025.bin +0 -0
- data/spec/bitcoin/fixtures/rawblock-131025.json +5063 -0
- data/spec/bitcoin/fixtures/rawblock-170.bin +0 -0
- data/spec/bitcoin/fixtures/rawblock-170.json +68 -0
- data/spec/bitcoin/fixtures/rawblock-9.bin +0 -0
- data/spec/bitcoin/fixtures/rawblock-9.json +39 -0
- data/spec/bitcoin/fixtures/rawblock-testnet-26478.bin +0 -0
- data/spec/bitcoin/fixtures/rawblock-testnet-26478.json +64 -0
- data/spec/bitcoin/fixtures/rawtx-01.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-01.json +27 -0
- data/spec/bitcoin/fixtures/rawtx-02.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-02.json +27 -0
- data/spec/bitcoin/fixtures/rawtx-03.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-03.json +48 -0
- data/spec/bitcoin/fixtures/rawtx-04.json +27 -0
- data/spec/bitcoin/fixtures/rawtx-0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-05.json +23 -0
- data/spec/bitcoin/fixtures/rawtx-14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.json +27 -0
- data/spec/bitcoin/fixtures/rawtx-406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602.json +23 -0
- data/spec/bitcoin/fixtures/rawtx-52250a162c7d03d2e1fbc5ebd1801a88612463314b55102171c5b5d817d2d7b2.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json +37 -0
- data/spec/bitcoin/fixtures/rawtx-c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73.json +24 -0
- data/spec/bitcoin/fixtures/rawtx-de35d060663750b3975b7997bde7fb76307cec5b270d12fcd9c4ad98b279c28c.json +23 -0
- data/spec/bitcoin/fixtures/rawtx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-a220adf1902c46a39db25a24bc4178b6a88440f977a7e2cabfdd8b5c1dd35cfb.json +27 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.json +41 -0
- data/spec/bitcoin/fixtures/reorg/blk_0_to_4.dat +0 -0
- data/spec/bitcoin/fixtures/reorg/blk_3A.dat +0 -0
- data/spec/bitcoin/fixtures/reorg/blk_4A.dat +0 -0
- data/spec/bitcoin/fixtures/reorg/blk_5A.dat +0 -0
- data/spec/bitcoin/fixtures/testnet/block_0.bin +0 -0
- data/spec/bitcoin/fixtures/testnet/block_1.bin +0 -0
- data/spec/bitcoin/fixtures/testnet/block_2.bin +0 -0
- data/spec/bitcoin/fixtures/testnet/block_3.bin +0 -0
- data/spec/bitcoin/fixtures/testnet/block_4.bin +0 -0
- data/spec/bitcoin/fixtures/testnet/block_5.bin +0 -0
- data/spec/bitcoin/fixtures/txdp-1.txt +32 -0
- data/spec/bitcoin/fixtures/txdp-2-signed.txt +19 -0
- data/spec/bitcoin/fixtures/txdp-2-unsigned.txt +14 -0
- data/spec/bitcoin/key_spec.rb +123 -0
- data/spec/bitcoin/network_spec.rb +48 -0
- data/spec/bitcoin/protocol/addr_spec.rb +68 -0
- data/spec/bitcoin/protocol/alert_spec.rb +20 -0
- data/spec/bitcoin/protocol/block_spec.rb +101 -0
- data/spec/bitcoin/protocol/inv_spec.rb +124 -0
- data/spec/bitcoin/protocol/ping_spec.rb +49 -0
- data/spec/bitcoin/protocol/tx_spec.rb +226 -0
- data/spec/bitcoin/protocol/version_spec.rb +77 -0
- data/spec/bitcoin/reorg_spec.rb +129 -0
- data/spec/bitcoin/script/opcodes_spec.rb +417 -0
- data/spec/bitcoin/script/script_spec.rb +246 -0
- data/spec/bitcoin/spec_helper.rb +36 -0
- data/spec/bitcoin/storage_spec.rb +229 -0
- data/spec/bitcoin/wallet/coinselector_spec.rb +35 -0
- data/spec/bitcoin/wallet/keygenerator_spec.rb +64 -0
- data/spec/bitcoin/wallet/keystore_spec.rb +188 -0
- data/spec/bitcoin/wallet/txdp_spec.rb +74 -0
- data/spec/bitcoin/wallet/wallet_spec.rb +207 -0
- metadata +295 -0
data/.gitignore
ADDED
data/COPYING
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Copyright (c) 2011 Julian Langschaedel <meta.rb@gmail.com>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
|
5
|
+
deal in the Software without restriction, including without limitation the
|
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
16
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Gemfile
ADDED
data/README.rdoc
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
= Bitcoin-ruby
|
|
2
|
+
|
|
3
|
+
This is a ruby library for interacting with the bitcoin protocol/network.
|
|
4
|
+
|
|
5
|
+
Some of the main features are:
|
|
6
|
+
|
|
7
|
+
* bitcoin utility functions for base58, ECC, etc. (Bitcoin::Util)
|
|
8
|
+
* parse/create (almost?) all protocol messages (Bitcoin::Protocol)
|
|
9
|
+
* connect to peers and exchange messages (Bitcoin::Network::Node, NODE)
|
|
10
|
+
* load the blockchain from the network and stay in sync (WITHOUT verification yet!)
|
|
11
|
+
* store and the blockchain and query for txouts (Bitcoin::Storage)
|
|
12
|
+
* script implementation, create/run scripts and verify signatures (Bitcoin::Script)
|
|
13
|
+
* create transactions (and even blocks!) (Bitcoin::Protocol, Bitcoin::Builder)
|
|
14
|
+
* manage keys (Bitcoin::Key) in a wallet (Bitcoin::Wallet, WALLET)
|
|
15
|
+
* there is even a highly experimental(!) Bitcoin::Gui
|
|
16
|
+
|
|
17
|
+
== Installation
|
|
18
|
+
|
|
19
|
+
We assume you already have a ruby 1.9 compatible interpreter and rubygems environment.
|
|
20
|
+
|
|
21
|
+
git clone https://github.com/lian/bitcoin-ruby.git; cd bitcoin-ruby
|
|
22
|
+
ruby -Ilib bin/bitcoin_node
|
|
23
|
+
|
|
24
|
+
if you want to install it system-wide, just build the gem and install it
|
|
25
|
+
|
|
26
|
+
gem build bitcoin-ruby.gemspec && gem install bitcoin-ruby-0.0.1.gem
|
|
27
|
+
|
|
28
|
+
now you can just call +bitcoin_node+ from anywhere.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
Note that some aspects of the library (such as networking, storage, etc.) need
|
|
32
|
+
additional dependencies which are not specified in the gemspec. The core requirements are
|
|
33
|
+
intentionally kept to a minimum, so nobody has to install unneeded dependencies.
|
|
34
|
+
|
|
35
|
+
* +eventmachine+ to run a node / connect to peers
|
|
36
|
+
* +sequel+, +sqlite3+/+pg+/+mysql+ to use a storage backend
|
|
37
|
+
* +em-dns+ or +nslookup+ to get peer addrs from DNS seeds
|
|
38
|
+
* +gir_ffi+ for the gui
|
|
39
|
+
* +bacon+ to run the specs
|
|
40
|
+
|
|
41
|
+
== Client
|
|
42
|
+
|
|
43
|
+
There is a NODE which connects to the network and downloads
|
|
44
|
+
the blockchain into a database. see Bitcoin::Network::Node.
|
|
45
|
+
|
|
46
|
+
It also opens an extra socket for clients to connect where they can call certain
|
|
47
|
+
methods, ask for information or register callbacks for events.
|
|
48
|
+
see Bitcoin::Network::CommandClient.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
There is a WALLET implementation to manage a set of keys, list balances and create
|
|
52
|
+
transactions. see Bitcoin::Wallet
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
== Library Usage
|
|
56
|
+
|
|
57
|
+
There are different aspects to the library which can be used separately or in combination.
|
|
58
|
+
Here are some Ideas of what you could do. There are also some scripts which you can run,
|
|
59
|
+
see EXAMPLES.
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
=== Keys/Addresses
|
|
63
|
+
|
|
64
|
+
Generate a Bitcoin::Key
|
|
65
|
+
|
|
66
|
+
key = Bitcoin::generate_key
|
|
67
|
+
key #=> [<privkey>, <pubkey>]
|
|
68
|
+
|
|
69
|
+
Get the address from a public key
|
|
70
|
+
|
|
71
|
+
address = Bitcoin::pubkey_to_address(key[1])
|
|
72
|
+
address #=> <bitcoin address>
|
|
73
|
+
|
|
74
|
+
Check if an address is valid
|
|
75
|
+
|
|
76
|
+
Bitcoin::valid_address?(address) #=> true
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
=== Blocks / Transactions parsing
|
|
80
|
+
|
|
81
|
+
Parse a Bitcoin::Protocol::Block
|
|
82
|
+
|
|
83
|
+
raw_block = File.open('spec/bitcoin/fixtures/rawblock-0.bin', 'rb') {|f| f.read}
|
|
84
|
+
blk = Bitcoin::Protocol::Block.new(raw_block)
|
|
85
|
+
blk.hash #=> 00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048
|
|
86
|
+
blk.tx.count #=> 1
|
|
87
|
+
blk.to_hash #=> ...
|
|
88
|
+
Bitcoin::Protocol::Block.from_json( blk.to_json )
|
|
89
|
+
|
|
90
|
+
Parse a Bitcoin::Protocol::Tx
|
|
91
|
+
|
|
92
|
+
raw_tx = File.open('spec/bitcoin/fixtures/rawtx-01.bin', 'rb') {|f| f.read}
|
|
93
|
+
tx = Bitcoin::Protocol::Tx.new(raw_tx)
|
|
94
|
+
tx.hash #=> 6e9dd16625b62cfcd4bf02edb89ca1f5a8c30c4b1601507090fb28e59f2d02b4
|
|
95
|
+
tx.in.size #=> 1
|
|
96
|
+
tx.out.size #=> 2
|
|
97
|
+
tx.to_hash #=> ...
|
|
98
|
+
Bitcoin::Protocol::Tx.from_json( tx.to_json )
|
|
99
|
+
|
|
100
|
+
Bitcoin::Script.new(tx.out[0].pk_script).to_string
|
|
101
|
+
#=> "OP_DUP OP_HASH160 b2e21c1db922e3bdc529de7b38b4c401399e9afd OP_EQUALVERIFY OP_CHECKSIG"
|
|
102
|
+
|
|
103
|
+
=== Transaction verification / Scripts
|
|
104
|
+
|
|
105
|
+
Get the matching transactions (in this example tx1 is the spending transaction)
|
|
106
|
+
|
|
107
|
+
rawtx1 = File.open("spec/bitcoin/fixtures/rawtx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16.bin", 'rb') {|f| f.read}
|
|
108
|
+
rawtx2 = File.open("spec/bitcoin/fixtures/rawtx-0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9.bin", 'rb') {|f| f.read}
|
|
109
|
+
tx1 = Bitcoin::Protocol::Tx.new(rawtx1)
|
|
110
|
+
tx2 = Bitcoin::Protocol::Tx.new(rawtx2)
|
|
111
|
+
|
|
112
|
+
Then simply ask the transaction to verify an input
|
|
113
|
+
|
|
114
|
+
tx1.verify_input_signature(0, tx2) #=> true
|
|
115
|
+
|
|
116
|
+
=== Scripts
|
|
117
|
+
|
|
118
|
+
If you want to control the Bitcoin::Script yourself, you can do so
|
|
119
|
+
|
|
120
|
+
txin = tx1.in.first
|
|
121
|
+
txout = tx2.out[txin.prev_out_index]
|
|
122
|
+
script = Bitcoin::Script.new(txin.script_sig + txout.pk_script)
|
|
123
|
+
|
|
124
|
+
result = script.run do |pubkey, sig, hash_type|
|
|
125
|
+
hash = tx1.signature_hash_for_input(0, nil, txout.pk_script)
|
|
126
|
+
Bitcoin.verify_signature(hash, sig, pubkey.unpack("H*")[0])
|
|
127
|
+
end
|
|
128
|
+
result #=> true
|
|
129
|
+
|
|
130
|
+
=== Create Transactions
|
|
131
|
+
|
|
132
|
+
TODO
|
|
133
|
+
|
|
134
|
+
=== Node / Network connections
|
|
135
|
+
|
|
136
|
+
The Bitcoin::Network::Node can connect to peers and download the blockchain into a
|
|
137
|
+
Bitcoin::Storage backend. For now it works completely self-contained:
|
|
138
|
+
|
|
139
|
+
node = Bitcoin::Network::Node.new(options) # options = {:network => :bitcoin, ...}
|
|
140
|
+
node.run
|
|
141
|
+
|
|
142
|
+
In the future you will be able to register callbacks to the node and control many aspects
|
|
143
|
+
of its operation yourself. Also see NODE.
|
|
144
|
+
|
|
145
|
+
If you want to implement your own node, see lib/bitcoin/connection.rb or
|
|
146
|
+
lib/bitcoin/network/node.rb for examples.
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
=== Storage / Database backends
|
|
150
|
+
|
|
151
|
+
There is support for multiple database backends, but currently the only stable one is
|
|
152
|
+
the Bitcoin::Storage::Backends::SequelStore backend. All backends implement the interface
|
|
153
|
+
defined in Bitcoin::Storage::Backends::StoreBase and return Bitcoin::Storage::Models.
|
|
154
|
+
|
|
155
|
+
store = Bitcoin::Storage.sequel(:db => "sqlite://bitcoin.db") # in-memory db
|
|
156
|
+
store.get_head #=> block
|
|
157
|
+
txouts = store.get_txouts_for_address("15yN7NPEpu82sHhB6TzCW5z5aXoamiKeGy")
|
|
158
|
+
txouts.first.value #=> 5000000000
|
|
159
|
+
txouts.first.type #=> :pubkey
|
|
160
|
+
txouts.first.get_address #=> "15yN7NPEpu82sHhB6TzCW5z5aXoamiKeGy"
|
|
161
|
+
|
|
162
|
+
See Bitcoin::Storage::Backends::StoreBase, Bitcoin::Storage::Backends::SequelStore
|
|
163
|
+
and Bitcoin::Storage::Models for details.
|
|
164
|
+
|
|
165
|
+
== Documentation
|
|
166
|
+
|
|
167
|
+
Always trying to improve, any help appreciated! If anything is unclear to you, let us know!
|
|
168
|
+
|
|
169
|
+
Documentation is generated using RDoc
|
|
170
|
+
|
|
171
|
+
rake rdoc
|
|
172
|
+
|
|
173
|
+
The specs are also a good place to see how something works.
|
|
174
|
+
|
|
175
|
+
== Specs
|
|
176
|
+
|
|
177
|
+
The specs can be run with
|
|
178
|
+
|
|
179
|
+
rake bacon
|
|
180
|
+
|
|
181
|
+
or, if you want to run a single spec
|
|
182
|
+
|
|
183
|
+
ruby spec/bitcoin/bitcoin_spec.rb
|
|
184
|
+
|
|
185
|
+
If you make changes to the code or add functionality, please also add specs.
|
|
186
|
+
|
|
187
|
+
== Development
|
|
188
|
+
|
|
189
|
+
If you are curious or like to participate in development, drop by \#bitcoin-ruby on irc.freenode.net!
|
data/Rakefile
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'bundler/gem_tasks'
|
|
3
|
+
rescue LoadError
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
PROJECT_SPECS = ( FileList['spec/bitcoin/bitcoin_spec.rb'] +
|
|
8
|
+
FileList['spec/bitcoin/protocol/*_spec.rb'] +
|
|
9
|
+
FileList['spec/bitcoin/script/*_spec.rb'] +
|
|
10
|
+
FileList['spec/bitcoin/wallet/*_spec.rb'] +
|
|
11
|
+
FileList['spec/bitcoin/*_spec.rb'] ).uniq
|
|
12
|
+
|
|
13
|
+
RUBY = 'ruby' unless defined?(RUBY)
|
|
14
|
+
|
|
15
|
+
task :default => :bacon
|
|
16
|
+
#
|
|
17
|
+
# test runner
|
|
18
|
+
#
|
|
19
|
+
desc 'Run all bacon specs with pretty output'
|
|
20
|
+
task :bacon do
|
|
21
|
+
require 'open3'
|
|
22
|
+
require 'scanf'
|
|
23
|
+
require 'matrix'
|
|
24
|
+
|
|
25
|
+
specs = PROJECT_SPECS
|
|
26
|
+
#specs.delete_if{|i| File.basename(i) == 'storage_spec.rb' } # skip for now
|
|
27
|
+
|
|
28
|
+
some_failed = false
|
|
29
|
+
specs_size = specs.size
|
|
30
|
+
len = specs.map{|s| s.size }.sort.last
|
|
31
|
+
total_tests = total_assertions = total_failures = total_errors = 0
|
|
32
|
+
totals = Vector[0, 0, 0, 0]
|
|
33
|
+
|
|
34
|
+
red, yellow, green = "\e[31m%s\e[0m", "\e[33m%s\e[0m", "\e[32m%s\e[0m"
|
|
35
|
+
left_format = "%4d/%d: %-#{len + 11}s"
|
|
36
|
+
spec_format = "%d specifications (%d requirements), %d failures, %d errors"
|
|
37
|
+
|
|
38
|
+
specs.each_with_index do |spec, idx|
|
|
39
|
+
print(left_format % [idx + 1, specs_size, spec])
|
|
40
|
+
|
|
41
|
+
Open3.popen3(RUBY, spec) do |sin, sout, serr|
|
|
42
|
+
out = sout.read.strip
|
|
43
|
+
err = serr.read.strip
|
|
44
|
+
|
|
45
|
+
# this is conventional, see spec/innate/state/fiber.rb for usage
|
|
46
|
+
if out =~ /^Bacon::Error: (needed .*)/
|
|
47
|
+
puts(yellow % ("%6s %s" % ['', $1]))
|
|
48
|
+
else
|
|
49
|
+
total = nil
|
|
50
|
+
|
|
51
|
+
out.each_line do |line|
|
|
52
|
+
scanned = line.scanf(spec_format)
|
|
53
|
+
|
|
54
|
+
next unless scanned.size == 4
|
|
55
|
+
|
|
56
|
+
total = Vector[*scanned]
|
|
57
|
+
break
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
if total
|
|
61
|
+
totals += total
|
|
62
|
+
tests, assertions, failures, errors = total_array = total.to_a
|
|
63
|
+
|
|
64
|
+
if tests > 0 && failures + errors == 0
|
|
65
|
+
puts((green % "%6d passed") % tests)
|
|
66
|
+
else
|
|
67
|
+
some_failed = true
|
|
68
|
+
puts(red % " failed")
|
|
69
|
+
puts out unless out.empty?
|
|
70
|
+
puts err unless err.empty?
|
|
71
|
+
end
|
|
72
|
+
else
|
|
73
|
+
some_failed = true
|
|
74
|
+
puts(red % " failed")
|
|
75
|
+
puts out unless out.empty?
|
|
76
|
+
puts err unless err.empty?
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
total_color = some_failed ? red : green
|
|
83
|
+
puts(total_color % (spec_format % totals.to_a))
|
|
84
|
+
exit 1 if some_failed
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
desc 'Generate RDoc documentation'
|
|
89
|
+
task :rdoc do
|
|
90
|
+
`rm -rf rdoc`
|
|
91
|
+
system("rdoc -o rdoc -m README.rdoc examples/ doc/ lib/ README.rdoc COPYING")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
desc 'Generate test coverage report'
|
|
96
|
+
task :coverage do
|
|
97
|
+
begin
|
|
98
|
+
require 'simplecov'
|
|
99
|
+
rescue LoadError
|
|
100
|
+
puts "Simplecov not found. Run `gem install simplecov` to install it."
|
|
101
|
+
exit
|
|
102
|
+
end
|
|
103
|
+
system "bacon #{PROJECT_SPECS.join(' ')}"
|
|
104
|
+
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
$:.unshift(File.dirname(__FILE__) + "/../lib")
|
|
3
|
+
|
|
4
|
+
require 'bitcoin'
|
|
5
|
+
require 'socket'
|
|
6
|
+
require 'json'
|
|
7
|
+
require 'rubydns'
|
|
8
|
+
require 'optparse'
|
|
9
|
+
|
|
10
|
+
Bitcoin::Network::Node # autoload to include Array#weighted_sample
|
|
11
|
+
|
|
12
|
+
DNS_OPTS = {
|
|
13
|
+
:name => nil,
|
|
14
|
+
:connect => "127.0.0.1:9999",
|
|
15
|
+
:port => 8333,
|
|
16
|
+
:cache => 1024,
|
|
17
|
+
:send => 16,
|
|
18
|
+
:interval => 10,
|
|
19
|
+
:ttl => nil,
|
|
20
|
+
:hosts => nil,
|
|
21
|
+
}
|
|
22
|
+
optparse = OptionParser.new do|opts|
|
|
23
|
+
opts.banner = "Usage: bitcoin_dns_seed [options] <domain>"
|
|
24
|
+
|
|
25
|
+
opts.on("-c", "--connect [HOST:PORT]",
|
|
26
|
+
"Connect to server (default: 127.0.0.1:9999)") do |connect|
|
|
27
|
+
DNS_OPTS[:connect] = connect
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
opts.on("-p", "--port [PORT]",
|
|
31
|
+
"Network default port each addr must match (default: 8333)") do |port|
|
|
32
|
+
DNS_OPTS[:port] = port.to_i
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
opts.on("-c", "--cache [SIZE]", "Cache addresses (default: 1024)") do |size|
|
|
36
|
+
DNS_OPTS[:cache] = size.to_i
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
opts.on("-s", "--send [SIZE]", "Send addresses (default: 16)") do |size|
|
|
40
|
+
DNS_OPTS[:send] = size.to_i
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
opts.on("-i", "--interval [SECONDS]", "Refresh addresses (default: 10)") do |s|
|
|
44
|
+
DNS_OPTS[:interval] = s.to_i
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
opts.on("-t", "--ttl [SECONDS]", "TTL to set on served records (default: relative to addr age)") do |t|
|
|
48
|
+
DNS_OPTS[:ttl] = t.to_i
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
opts.on("--hosts [HOSTS]", "Additional hosts file with name => addr mappings") do |h|
|
|
52
|
+
DNS_OPTS[:hosts] = h
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
|
56
|
+
puts opts
|
|
57
|
+
exit
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
optparse.parse!
|
|
61
|
+
|
|
62
|
+
DNS_OPTS[:domain] = ARGV.shift
|
|
63
|
+
unless DNS_OPTS[:domain]
|
|
64
|
+
puts optparse
|
|
65
|
+
exit
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class RubyDNS::Server
|
|
70
|
+
attr_accessor :addrs
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
class AddrFetcher < EM::Connection
|
|
74
|
+
def initialize(dns)
|
|
75
|
+
@dns = dns
|
|
76
|
+
@dns.addrs ||= []
|
|
77
|
+
@buf = BufferedTokenizer.new("\x00")
|
|
78
|
+
send_data(["addrs", DNS_OPTS[:cache].to_s].to_json)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def receive_data(data)
|
|
82
|
+
@buf.extract(data).each do |packet|
|
|
83
|
+
json = JSON.load(packet)[1]
|
|
84
|
+
@dns.logger.info { "received #{json.size} new addrs" }
|
|
85
|
+
@dns.addrs += json.select{|a| a[1] == DNS_OPTS[:port]}
|
|
86
|
+
@dns.addrs.uniq! {|a| a[0]}
|
|
87
|
+
pop = @dns.addrs.size - DNS_OPTS[:cache]
|
|
88
|
+
@dns.addrs.pop(pop) if pop > 0
|
|
89
|
+
@dns.logger.debug { "addr pool size now #{@dns.addrs.size}" }
|
|
90
|
+
close_connection
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def self.run(host, port, dns, interval = 30)
|
|
95
|
+
EM.connect(host, port, self, dns)
|
|
96
|
+
EM.add_periodic_timer(interval) do
|
|
97
|
+
EM.connect(host, port, self, dns)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
dns = RubyDNS::Server.new
|
|
103
|
+
dns.match(DNS_OPTS[:domain], :A) do |transaction|
|
|
104
|
+
addrs = dns.addrs.weighted_sample(DNS_OPTS[:send]) {|addr| 10800 - addr[2] }.uniq
|
|
105
|
+
addrs.each do |addr|
|
|
106
|
+
begin
|
|
107
|
+
ttl = DNS_OPTS[:ttl] || ((10800 - addr[2]) / 30)
|
|
108
|
+
transaction.respond!(addr[0], :ttl => ttl)
|
|
109
|
+
rescue
|
|
110
|
+
# ignore faulty addrs ("localhost" etc)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
if DNS_OPTS[:hosts]
|
|
116
|
+
dns.logger.info { "serving additional addrs from file" }
|
|
117
|
+
File.read(DNS_OPTS[:hosts]).each_line do |line|
|
|
118
|
+
dns.logger.debug { line.strip }
|
|
119
|
+
addr, *names = line.split(/\s+/)
|
|
120
|
+
names.each {|n| dns.match(n, :A) {|t| t.respond!(addr) } }
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
EM.run do
|
|
125
|
+
EventMachine.open_datagram_socket("0.0.0.0", 53, RubyDNS::UDPHandler, dns)
|
|
126
|
+
EventMachine.start_server("0.0.0.0", 53, RubyDNS::TCPHandler, dns)
|
|
127
|
+
dns.logger.info { "DNS Server listening on 0.0.0.0:53" }
|
|
128
|
+
|
|
129
|
+
timer = AddrFetcher.run(*DNS_OPTS[:connect].split(":"), dns, DNS_OPTS[:interval])
|
|
130
|
+
end
|