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
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
module Bitcoin
|
|
2
|
+
|
|
3
|
+
# Optional DSL to help create blocks and transactions.
|
|
4
|
+
#
|
|
5
|
+
# see also BlockBuilder, TxBuilder, TxInBuilder, TxOutBuilder, ScriptBuilder
|
|
6
|
+
module Builder
|
|
7
|
+
|
|
8
|
+
# build a Bitcoin::Protocol::Block matching the given +target+.
|
|
9
|
+
# see BlockBuilder for details.
|
|
10
|
+
def blk(target = "00".ljust(32, 'f'))
|
|
11
|
+
c = BlockBuilder.new
|
|
12
|
+
yield c
|
|
13
|
+
c.block(target)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# build a Bitcoin::Protocol::Tx.
|
|
17
|
+
# see TxBuilder for details.
|
|
18
|
+
def tx
|
|
19
|
+
c = TxBuilder.new
|
|
20
|
+
yield c
|
|
21
|
+
c.tx
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# build a Bitcoin::Script.
|
|
25
|
+
# see ScriptBuilder for details.
|
|
26
|
+
def script
|
|
27
|
+
c = ScriptBuilder.new
|
|
28
|
+
yield c
|
|
29
|
+
c.script
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# DSL to create a Bitcoin::Protocol::Block used by Builder#blk.
|
|
33
|
+
# block = blk("00".ljust(32, 'f')) do |b|
|
|
34
|
+
# b.prev_block "\x00"*32
|
|
35
|
+
# b.tx do |t|
|
|
36
|
+
# t.input {|i| i.coinbase }
|
|
37
|
+
# t.output do |o|
|
|
38
|
+
# o.value 5000000000;
|
|
39
|
+
# o.script do |s|
|
|
40
|
+
# s.type :address
|
|
41
|
+
# s.recipient Bitcoin::Key.generate.addr
|
|
42
|
+
# end
|
|
43
|
+
# end
|
|
44
|
+
# end
|
|
45
|
+
# end
|
|
46
|
+
class BlockBuilder
|
|
47
|
+
|
|
48
|
+
def initialize
|
|
49
|
+
@block = Bitcoin::P::Block.new(nil)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# specify block version. this is usually not necessary. defaults to 1.
|
|
53
|
+
def version v
|
|
54
|
+
@version = v
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# set the hash of the previous block.
|
|
58
|
+
def prev_block hash
|
|
59
|
+
@prev_block = hash
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# add transactions to the block (see TxBuilder).
|
|
63
|
+
def tx
|
|
64
|
+
c = TxBuilder.new
|
|
65
|
+
yield c
|
|
66
|
+
@block.tx << c.tx
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# create the block according to values specified via DSL.
|
|
70
|
+
def block target
|
|
71
|
+
@block.ver = @version || 1
|
|
72
|
+
@block.prev_block = [@prev_block].pack("H*").reverse
|
|
73
|
+
@block.mrkl_root = @mrkl_root
|
|
74
|
+
@block.time = Time.now.to_i
|
|
75
|
+
@block.nonce = 0
|
|
76
|
+
@block.mrkl_root = [Bitcoin.hash_mrkl_tree(@block.tx.map {|t|
|
|
77
|
+
t.hash }).last].pack("H*")
|
|
78
|
+
find_hash(target)
|
|
79
|
+
Bitcoin::P::Block.new(@block.to_payload)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
# increment nonce/time to find a block hash matching the +target+.
|
|
85
|
+
def find_hash target
|
|
86
|
+
@block.bits = Bitcoin.encode_compact_bits(target)
|
|
87
|
+
t = Time.now
|
|
88
|
+
@block.recalc_block_hash
|
|
89
|
+
until @block.hash < target
|
|
90
|
+
@block.nonce += 1
|
|
91
|
+
@block.recalc_block_hash
|
|
92
|
+
if @block.nonce == 100000
|
|
93
|
+
if t
|
|
94
|
+
tt = 1 / ((Time.now - t) / 100000) / 1000
|
|
95
|
+
print "\r%.2f khash/s" % tt
|
|
96
|
+
end
|
|
97
|
+
t = Time.now
|
|
98
|
+
@block.time = Time.now.to_i
|
|
99
|
+
@block.nonce = 0
|
|
100
|
+
$stdout.flush
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# DSL to create Bitcoin::Protocol::Tx used by Builder#tx.
|
|
108
|
+
# tx = tx do |t|
|
|
109
|
+
# t.input do |i|
|
|
110
|
+
# i.prev_out prev_tx # previous transaction
|
|
111
|
+
# i.prev_out_index 0 # index of previous output
|
|
112
|
+
# i.signature_key key # Bitcoin::Key used to sign the input
|
|
113
|
+
# end
|
|
114
|
+
# t.output do |o|
|
|
115
|
+
# o.value 12345 # 0.00012345 BTC
|
|
116
|
+
# o.script {|s| s.type :address; s.recipient key.addr }
|
|
117
|
+
# end
|
|
118
|
+
# end
|
|
119
|
+
class TxBuilder
|
|
120
|
+
|
|
121
|
+
def initialize
|
|
122
|
+
@tx = Bitcoin::P::Tx.new(nil)
|
|
123
|
+
@tx.ver, @tx.lock_time = 1, 0
|
|
124
|
+
@ins, @outs = [], []
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# specify tx version. this is usually not necessary. defaults to 1.
|
|
128
|
+
def version n
|
|
129
|
+
@tx.ver = n
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# specify tx lock_time. this is usually not necessary. defaults to 0.
|
|
133
|
+
def lock_time n
|
|
134
|
+
@tx.lock_time = n
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# add an input to the transaction (see TxInBuilder).
|
|
138
|
+
def input
|
|
139
|
+
c = TxInBuilder.new
|
|
140
|
+
yield c
|
|
141
|
+
@ins << c
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# add an output to the transaction (see TxOutBuilder).
|
|
145
|
+
def output
|
|
146
|
+
c = TxOutBuilder.new
|
|
147
|
+
yield c
|
|
148
|
+
@outs << c
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# create the transaction according to values specified via DSL and sign inputs.
|
|
152
|
+
def tx
|
|
153
|
+
@ins.each {|i| @tx.add_in(i.txin) }
|
|
154
|
+
@outs.each {|o| @tx.add_out(o.txout) }
|
|
155
|
+
@ins.each_with_index do |inc, i|
|
|
156
|
+
if @tx.in[i].coinbase?
|
|
157
|
+
script_sig = [inc.coinbase_data].pack("H*")
|
|
158
|
+
@tx.in[i].script_sig_length = script_sig.bytesize
|
|
159
|
+
@tx.in[i].script_sig = script_sig
|
|
160
|
+
next
|
|
161
|
+
end
|
|
162
|
+
prev_tx = inc.instance_variable_get(:@prev_out)
|
|
163
|
+
sig_hash = @tx.signature_hash_for_input(i, prev_tx)
|
|
164
|
+
sig = inc.key.sign(sig_hash)
|
|
165
|
+
script_sig = Bitcoin::Script.to_signature_pubkey_script(sig, [inc.key.pub].pack("H*"))
|
|
166
|
+
@tx.in[i].script_sig_length = script_sig.bytesize
|
|
167
|
+
@tx.in[i].script_sig = script_sig
|
|
168
|
+
raise "Signature error" unless @tx.verify_input_signature(i, prev_tx)
|
|
169
|
+
end
|
|
170
|
+
Bitcoin::P::Tx.new(@tx.to_payload)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# create a Bitcoin::Protocol::TxIn used by TxBuilder#input.
|
|
175
|
+
#
|
|
176
|
+
# inputs can be either 'coinbase', in which case they only need to specify #coinbase,
|
|
177
|
+
# or they have to define a #prev_out, #prev_out_index and #signature key.
|
|
178
|
+
class TxInBuilder
|
|
179
|
+
attr_reader :key, :coinbase_data
|
|
180
|
+
|
|
181
|
+
def initialize
|
|
182
|
+
@txin = Bitcoin::P::TxIn.new
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# previous transaction that contains the output we want to use.
|
|
186
|
+
def prev_out tx
|
|
187
|
+
@prev_out = tx
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# index of the output in the #prev_out transaction.
|
|
191
|
+
def prev_out_index i
|
|
192
|
+
@prev_out_index = i
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# specify sequence. this is usually not needed.
|
|
196
|
+
def sequence s
|
|
197
|
+
@sequence = s
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Bitcoin::Key used to sign the signature_hash for the input.
|
|
201
|
+
# see Bitcoin::Script.signature_hash_for_input and Bitcoin::Key.sign.
|
|
202
|
+
def signature_key key
|
|
203
|
+
@key = key
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# specify that this is a coinbase input. optionally set +data+.
|
|
207
|
+
def coinbase data = nil
|
|
208
|
+
@coinbase_data = data || OpenSSL::Random.random_bytes(32)
|
|
209
|
+
@prev_out = nil
|
|
210
|
+
@prev_out_index = 4294967295
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# create the txin according to values specified via DSL
|
|
214
|
+
def txin
|
|
215
|
+
@txin.prev_out = (@prev_out ? @prev_out.binary_hash : "\x00"*32)
|
|
216
|
+
@txin.prev_out_index = @prev_out_index
|
|
217
|
+
@txin.sequence = @sequence || "\xff\xff\xff\xff"
|
|
218
|
+
@txin
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# create a Bitcoin::Script used by TxOutBuilder#script.
|
|
223
|
+
class ScriptBuilder
|
|
224
|
+
attr_reader :script
|
|
225
|
+
|
|
226
|
+
def initialize
|
|
227
|
+
@type = nil
|
|
228
|
+
@script = nil
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# script type (:pubkey, :address/hash160, :multisig).
|
|
232
|
+
def type type
|
|
233
|
+
@type = type.to_sym
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# recipient(s) of the script.
|
|
237
|
+
# depending on the #type, either an address, hash160 pubkey, etc.
|
|
238
|
+
def recipient *data
|
|
239
|
+
@script = Bitcoin::Script.send("to_#{@type}_script", *data)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# create a Bitcoin::Protocol::TxOut used by TxBuilder#output.
|
|
244
|
+
class TxOutBuilder
|
|
245
|
+
attr_reader :txout
|
|
246
|
+
|
|
247
|
+
def initialize
|
|
248
|
+
@txout = Bitcoin::P::TxOut.new
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# set output value (in base units / "satoshis")
|
|
252
|
+
def value value
|
|
253
|
+
@txout.value = value
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# add a script to the output (see ScriptBuilder).
|
|
257
|
+
def script &block
|
|
258
|
+
c = ScriptBuilder.new
|
|
259
|
+
yield c
|
|
260
|
+
@txout.pk_script = c.script
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
end
|
|
266
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
module Bitcoin
|
|
3
|
+
|
|
4
|
+
# Load config files, merge options, etc.
|
|
5
|
+
#
|
|
6
|
+
# Multiple config files are loaded in order, and their settings merged into an
|
|
7
|
+
# existing +options+ hash.
|
|
8
|
+
#
|
|
9
|
+
# Each config file defines one or more +categories+ which hold the actual settings.
|
|
10
|
+
# Which categories are loaded, and in what order, is specified when you load
|
|
11
|
+
# the config (ie. the order in the file doesn't matter).
|
|
12
|
+
# The default category "all" is always used, and is always the first
|
|
13
|
+
# (gets overridden by all others)
|
|
14
|
+
module Config
|
|
15
|
+
|
|
16
|
+
CONFIG_PATHS = "./bitcoin-ruby.yml:~/.bitcoin-ruby.yml:/etc/bitcoin-ruby.yml"
|
|
17
|
+
|
|
18
|
+
# Load +categories+ from all files at +paths+ into given +options+ hash.
|
|
19
|
+
def self.load(options, categories = [], paths = CONFIG_PATHS)
|
|
20
|
+
paths.split(":").reverse.each do |path|
|
|
21
|
+
path.sub!("~", ENV["HOME"])
|
|
22
|
+
next unless File.exist?(path)
|
|
23
|
+
options = load_file(options, path, categories)
|
|
24
|
+
end
|
|
25
|
+
options
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Load categories +c+ of a single config +file+ into given +options+ hash.
|
|
29
|
+
def self.load_file(options, file, c = [])
|
|
30
|
+
categories = YAML::load_file(file)
|
|
31
|
+
[:all, *(c.is_a?(Array) ? c : [c])].each do |category|
|
|
32
|
+
options = merge(options, categories[category.to_s]) if categories[category.to_s]
|
|
33
|
+
end
|
|
34
|
+
options
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Deep-merge hash +b+ into +a+.
|
|
38
|
+
def self.merge(a, b)
|
|
39
|
+
return a unless b
|
|
40
|
+
symbolize(a).merge(symbolize(b)) do |k, o, n|
|
|
41
|
+
if o.is_a?(Hash) && n.is_a?(Hash)
|
|
42
|
+
merge(symbolize(o), symbolize(n))
|
|
43
|
+
else
|
|
44
|
+
n
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Turn all keys in +hash+ into symbols.
|
|
50
|
+
def self.symbolize(hash)
|
|
51
|
+
Hash[hash.map{|k,v|[k.to_sym,v]}]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
require 'eventmachine'
|
|
3
|
+
require 'bitcoin'
|
|
4
|
+
|
|
5
|
+
module Bitcoin
|
|
6
|
+
|
|
7
|
+
module ConnectionHandler
|
|
8
|
+
def hth(h); h.unpack("H*")[0]; end
|
|
9
|
+
def htb(h); [h].pack("H*"); end
|
|
10
|
+
|
|
11
|
+
def on_inv_transaction(hash)
|
|
12
|
+
p ['inv transaction', hth(hash)]
|
|
13
|
+
pkt = Protocol.getdata_pkt(:tx, [hash])
|
|
14
|
+
send_data(pkt)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def on_inv_block(hash)
|
|
18
|
+
p ['inv block', hth(hash)]
|
|
19
|
+
pkt = Protocol.getdata_pkt(:block, [hash])
|
|
20
|
+
send_data(pkt)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def on_get_transaction(hash)
|
|
24
|
+
p ['get transaction', hth(hash)]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def on_get_block(hash)
|
|
28
|
+
p ['get block', hth(hash)]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def on_addr(addr)
|
|
32
|
+
p ['addr', addr, addr.alive?]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def on_tx(tx)
|
|
36
|
+
p ['tx', tx.hash]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def on_block(block)
|
|
40
|
+
p ['block', block.hash]
|
|
41
|
+
#p block.payload.each_byte.map{|i| "%02x" % [i] }.join(" ")
|
|
42
|
+
#puts block.to_json
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def on_version(version)
|
|
46
|
+
p [@sockaddr, 'version', version, version.timestamp - Time.now.to_i]
|
|
47
|
+
send_data( Protocol.verack_pkt )
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def on_handshake_complete
|
|
51
|
+
p [@sockaddr, 'handshake complete']
|
|
52
|
+
@connected = true
|
|
53
|
+
|
|
54
|
+
query_blocks
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def query_blocks
|
|
58
|
+
start = ("\x00"*32)
|
|
59
|
+
stop = ("\x00"*32)
|
|
60
|
+
pkt = Protocol.pkt("getblocks", "\x00" + start + stop )
|
|
61
|
+
send_data(pkt)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def on_handshake_begin
|
|
65
|
+
block = 127953
|
|
66
|
+
from = "127.0.0.1:8333"
|
|
67
|
+
from_id = Bitcoin::Protocol::Uniq
|
|
68
|
+
to = @sockaddr.reverse.join(":")
|
|
69
|
+
# p "==", from_id, from, to, block
|
|
70
|
+
pkt = Protocol.version_pkt(from_id, from, to, block)
|
|
71
|
+
p ['sending version pkt', pkt]
|
|
72
|
+
send_data(pkt)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class Connection < EM::Connection
|
|
78
|
+
include ConnectionHandler
|
|
79
|
+
|
|
80
|
+
def initialize(host, port, connections)
|
|
81
|
+
@sockaddr = [port, host]
|
|
82
|
+
@connections = connections
|
|
83
|
+
@parser = Bitcoin::Protocol::Parser.new( self )
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def post_init
|
|
87
|
+
p ['connected', @sockaddr]
|
|
88
|
+
EM.schedule{ on_handshake_begin }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def receive_data(data)
|
|
92
|
+
@parser.parse(data)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def unbind
|
|
96
|
+
p ['disconnected', @sockaddr]
|
|
97
|
+
self.class.connect_random_from_dns(@connections)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def self.connect(host, port, connections)
|
|
101
|
+
EM.connect(host, port, self, host, port, connections)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def self.connect_random_from_dns(connections)
|
|
105
|
+
seeds = Bitcoin.network[:dns_seeds]
|
|
106
|
+
if seeds.any?
|
|
107
|
+
host = `nslookup #{seeds.sample}`.scan(/Address\: (.+)$/).flatten.sample
|
|
108
|
+
connect(host, Bitcoin::network[:default_port], connections)
|
|
109
|
+
else
|
|
110
|
+
raise "No DNS seeds available. Provide IP, configure seeds, or use different network."
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if $0 == __FILE__
|
|
118
|
+
EM.run do
|
|
119
|
+
|
|
120
|
+
connections = []
|
|
121
|
+
#Bitcoin::Connection.connect('127.0.0.1', 8333, connections)
|
|
122
|
+
#Bitcoin::Connection.connect('217.157.1.202', 8333, connections)
|
|
123
|
+
Bitcoin::Connection.connect_random_from_dns(connections)
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
end
|