bitcoin-ruby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|