bitcoin-ruby 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -1
- data/Gemfile +21 -0
- data/README.rdoc +85 -25
- data/Rakefile +7 -3
- data/bin/bitcoin_node +39 -42
- data/bin/bitcoin_shell +1 -0
- data/bin/bitcoin_wallet +129 -53
- data/bitcoin-ruby.gemspec +4 -7
- data/concept-examples/blockchain-pow.rb +1 -1
- data/doc/CONFIG.rdoc +5 -5
- data/doc/EXAMPLES.rdoc +9 -5
- data/doc/NAMECOIN.rdoc +34 -0
- data/doc/NODE.rdoc +147 -10
- data/examples/balance.rb +10 -4
- data/examples/bbe_verify_tx.rb +7 -2
- data/examples/forwarder.rb +73 -0
- data/examples/generate_tx.rb +34 -0
- data/examples/simple_network_monitor_and_util.rb +187 -0
- data/examples/verify_tx.rb +1 -1
- data/lib/bitcoin.rb +308 -18
- data/lib/bitcoin/builder.rb +62 -36
- data/lib/bitcoin/config.rb +2 -0
- data/lib/bitcoin/connection.rb +11 -8
- data/lib/bitcoin/electrum/mnemonic.rb +162 -0
- data/lib/bitcoin/ffi/openssl.rb +187 -21
- data/lib/bitcoin/gui/addr_view.rb +2 -0
- data/lib/bitcoin/gui/conn_view.rb +2 -0
- data/lib/bitcoin/gui/connection.rb +2 -0
- data/lib/bitcoin/gui/em_gtk.rb +2 -0
- data/lib/bitcoin/gui/gui.rb +2 -0
- data/lib/bitcoin/gui/helpers.rb +2 -0
- data/lib/bitcoin/gui/tree_view.rb +2 -0
- data/lib/bitcoin/gui/tx_view.rb +2 -0
- data/lib/bitcoin/key.rb +77 -11
- data/lib/bitcoin/litecoin.rb +81 -0
- data/lib/bitcoin/logger.rb +20 -1
- data/lib/bitcoin/namecoin.rb +279 -0
- data/lib/bitcoin/network/command_client.rb +7 -6
- data/lib/bitcoin/network/command_handler.rb +229 -43
- data/lib/bitcoin/network/connection_handler.rb +182 -70
- data/lib/bitcoin/network/node.rb +231 -106
- data/lib/bitcoin/protocol.rb +44 -23
- data/lib/bitcoin/protocol/address.rb +5 -3
- data/lib/bitcoin/protocol/alert.rb +3 -4
- data/lib/bitcoin/protocol/aux_pow.rb +123 -0
- data/lib/bitcoin/protocol/block.rb +98 -18
- data/lib/bitcoin/protocol/handler.rb +6 -5
- data/lib/bitcoin/protocol/parser.rb +44 -19
- data/lib/bitcoin/protocol/tx.rb +105 -52
- data/lib/bitcoin/protocol/txin.rb +39 -19
- data/lib/bitcoin/protocol/txout.rb +28 -13
- data/lib/bitcoin/protocol/version.rb +16 -7
- data/lib/bitcoin/script.rb +579 -122
- data/lib/bitcoin/storage/{dummy.rb → dummy/dummy_store.rb} +8 -14
- data/lib/bitcoin/storage/models.rb +20 -7
- data/lib/bitcoin/storage/{sequel_store/sequel_migrations.rb → sequel/migrations.rb} +22 -7
- data/lib/bitcoin/storage/sequel/migrations/001_base_schema.rb +52 -0
- data/lib/bitcoin/storage/sequel/migrations/002_tx.rb +50 -0
- data/lib/bitcoin/storage/sequel/migrations/003_change_txin_script_sig_to_blob.rb +18 -0
- data/lib/bitcoin/storage/sequel/sequel_store.rb +436 -0
- data/lib/bitcoin/storage/storage.rb +233 -28
- data/lib/bitcoin/storage/utxo/migrations/001_base_schema.rb +52 -0
- data/lib/bitcoin/storage/utxo/migrations/002_utxo.rb +18 -0
- data/lib/bitcoin/storage/utxo/utxo_store.rb +361 -0
- data/lib/bitcoin/validation.rb +369 -0
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin/wallet/coinselector.rb +3 -0
- data/lib/bitcoin/wallet/keygenerator.rb +3 -1
- data/lib/bitcoin/wallet/keystore.rb +6 -2
- data/lib/bitcoin/wallet/txdp.rb +6 -4
- data/lib/bitcoin/wallet/wallet.rb +54 -16
- data/spec/bitcoin/bitcoin_spec.rb +48 -3
- data/spec/bitcoin/builder_spec.rb +40 -17
- data/spec/bitcoin/fixtures/000000000000056b1a3d84a1e2b33cde8915a4b61c0cae14fca6d3e1490b4f98.json +3697 -0
- data/spec/bitcoin/fixtures/03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json +23 -0
- data/spec/bitcoin/fixtures/0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json +24 -0
- data/spec/bitcoin/fixtures/0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json +37 -0
- data/spec/bitcoin/fixtures/315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json +31 -0
- data/spec/bitcoin/fixtures/35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json +27 -0
- data/spec/bitcoin/fixtures/3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json +72 -0
- data/spec/bitcoin/fixtures/3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json +27 -0
- data/spec/bitcoin/fixtures/514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json +24 -0
- data/spec/bitcoin/fixtures/51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json +30 -0
- data/spec/bitcoin/fixtures/69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json +28 -0
- data/spec/bitcoin/fixtures/7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json +27 -0
- data/spec/bitcoin/fixtures/761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json +27 -0
- data/spec/bitcoin/fixtures/aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json +27 -0
- data/spec/bitcoin/fixtures/bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json +34 -0
- data/spec/bitcoin/fixtures/block-testnet-0000000000ac85bb2530a05a4214a387e6be02b22d3348abc5e7a5d9c4ce8dab.bin +0 -0
- data/spec/bitcoin/fixtures/cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json +24 -0
- data/spec/bitcoin/fixtures/ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json +41 -0
- data/spec/bitcoin/fixtures/f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json +23 -0
- data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.bin +0 -0
- data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.json +43 -0
- data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.bin +0 -0
- data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.json +67 -0
- data/spec/bitcoin/fixtures/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.bin +0 -0
- data/spec/bitcoin/fixtures/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.json +39 -0
- data/spec/bitcoin/fixtures/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.bin +0 -0
- data/spec/bitcoin/fixtures/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.json +39 -0
- data/spec/bitcoin/fixtures/rawblock-auxpow.bin +0 -0
- data/spec/bitcoin/fixtures/tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json +30 -0
- data/spec/bitcoin/fixtures/tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json +23 -0
- data/spec/bitcoin/fixtures/tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json +30 -0
- data/spec/bitcoin/fixtures/tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json +28 -0
- data/spec/bitcoin/key_spec.rb +128 -3
- data/spec/bitcoin/namecoin_spec.rb +182 -0
- data/spec/bitcoin/network_spec.rb +5 -3
- data/spec/bitcoin/node/command_api_spec.rb +376 -0
- data/spec/bitcoin/protocol/addr_spec.rb +2 -0
- data/spec/bitcoin/protocol/alert_spec.rb +2 -0
- data/spec/bitcoin/protocol/aux_pow_spec.rb +44 -0
- data/spec/bitcoin/protocol/block_spec.rb +134 -39
- data/spec/bitcoin/protocol/getblocks_spec.rb +32 -0
- data/spec/bitcoin/protocol/inv_spec.rb +10 -8
- data/spec/bitcoin/protocol/notfound_spec.rb +31 -0
- data/spec/bitcoin/protocol/ping_spec.rb +2 -0
- data/spec/bitcoin/protocol/tx_spec.rb +83 -17
- data/spec/bitcoin/protocol/version_spec.rb +7 -5
- data/spec/bitcoin/script/opcodes_spec.rb +412 -133
- data/spec/bitcoin/script/script_spec.rb +112 -13
- data/spec/bitcoin/spec_helper.rb +68 -0
- data/spec/bitcoin/storage/reorg_spec.rb +199 -0
- data/spec/bitcoin/storage/storage_spec.rb +337 -0
- data/spec/bitcoin/storage/validation_spec.rb +261 -0
- data/spec/bitcoin/wallet/coinselector_spec.rb +10 -7
- data/spec/bitcoin/wallet/keygenerator_spec.rb +2 -0
- data/spec/bitcoin/wallet/keystore_spec.rb +2 -0
- data/spec/bitcoin/wallet/txdp_spec.rb +2 -0
- data/spec/bitcoin/wallet/wallet_spec.rb +91 -58
- metadata +105 -51
- data/lib/bitcoin/storage/sequel.rb +0 -335
- data/spec/bitcoin/fixtures/0d0affb5964abe804ffe85e53f1dbb9f29e406aa3046e2db04fba240e63c7fdd.json +0 -27
- data/spec/bitcoin/fixtures/477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590.json +0 -27
- data/spec/bitcoin/reorg_spec.rb +0 -129
- data/spec/bitcoin/storage_spec.rb +0 -229
@@ -1,335 +0,0 @@
|
|
1
|
-
Bitcoin.require_dependency :sequel, message:
|
2
|
-
"Note: You will also need an adapter for your database like sqlite3, mysql2, postgresql"
|
3
|
-
require 'bitcoin/storage/sequel_store/sequel_migrations'
|
4
|
-
|
5
|
-
module Bitcoin::Storage::Backends
|
6
|
-
|
7
|
-
# Storage backend using Sequel to connect to arbitrary SQL databases.
|
8
|
-
# Inherits from StoreBase and implements its interface.
|
9
|
-
class SequelStore < StoreBase
|
10
|
-
|
11
|
-
|
12
|
-
# possible script types
|
13
|
-
SCRIPT_TYPES = [:unknown, :pubkey, :hash160, :multisig, :p2sh]
|
14
|
-
|
15
|
-
# sequel database connection
|
16
|
-
attr_accessor :db
|
17
|
-
|
18
|
-
include Bitcoin::Storage::Backends::SequelMigrations
|
19
|
-
|
20
|
-
# create sequel store with given +config+
|
21
|
-
def initialize config, *args
|
22
|
-
@config = config
|
23
|
-
connect
|
24
|
-
super config, *args
|
25
|
-
end
|
26
|
-
|
27
|
-
# connect to database
|
28
|
-
def connect
|
29
|
-
{:sqlite => "sqlite3", :postgres => "pg", :mysql => "mysql",
|
30
|
-
}.each do |adapter, name|
|
31
|
-
if @config[:db].split(":").first == adapter.to_s
|
32
|
-
Bitcoin.require_dependency name, gem: name
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
@db = Sequel.connect(@config[:db])
|
37
|
-
migrate
|
38
|
-
end
|
39
|
-
|
40
|
-
# reset database; delete all data
|
41
|
-
def reset
|
42
|
-
[:blk, :blk_tx, :tx, :txin, :txout].each {|table| @db[table].delete}
|
43
|
-
end
|
44
|
-
|
45
|
-
# persist given block +blk+ to storage.
|
46
|
-
def persist_block blk, chain, depth
|
47
|
-
@db.transaction do
|
48
|
-
attrs = {
|
49
|
-
:hash => htb(blk.hash).to_sequel_blob,
|
50
|
-
:depth => depth,
|
51
|
-
:chain => chain,
|
52
|
-
:version => blk.ver,
|
53
|
-
:prev_hash => blk.prev_block.reverse.to_sequel_blob,
|
54
|
-
:mrkl_root => blk.mrkl_root.reverse.to_sequel_blob,
|
55
|
-
:time => blk.time,
|
56
|
-
:bits => blk.bits,
|
57
|
-
:nonce => blk.nonce,
|
58
|
-
:blk_size => blk.to_payload.bytesize,
|
59
|
-
}
|
60
|
-
existing = @db[:blk].filter(:hash => htb(blk.hash).to_sequel_blob)
|
61
|
-
if existing.any?
|
62
|
-
existing.update attrs
|
63
|
-
else
|
64
|
-
block_id = @db[:blk].insert(attrs)
|
65
|
-
blk.tx.each_with_index do |tx, idx|
|
66
|
-
tx_id = store_tx(tx)
|
67
|
-
raise "Error saving tx #{tx.hash} in block #{blk.hash}" unless tx_id
|
68
|
-
@db[:blk_tx].insert({
|
69
|
-
:blk_id => block_id,
|
70
|
-
:tx_id => tx_id,
|
71
|
-
:idx => idx,
|
72
|
-
})
|
73
|
-
end
|
74
|
-
end
|
75
|
-
begin
|
76
|
-
@db[:blk].where(:prev_hash => htb(blk.hash).to_sequel_blob, :chain => ORPHAN).each do |b|
|
77
|
-
log.debug { "re-org orphan #{hth(b[:hash])}" }
|
78
|
-
begin
|
79
|
-
store_block(get_block(hth(b[:hash])))
|
80
|
-
rescue SystemStackError
|
81
|
-
EM.defer { store_block(get_block(hth(b[:hash]))) } if EM.reactor_running?
|
82
|
-
end
|
83
|
-
end
|
84
|
-
rescue
|
85
|
-
p $!
|
86
|
-
end
|
87
|
-
log.info { "block #{blk.hash} (#{depth}, #{['main', 'side', 'orphan'][chain]})" }
|
88
|
-
return depth, chain
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# update +attrs+ for block with given +hash+.
|
93
|
-
def update_blocks updates
|
94
|
-
@db.transaction do
|
95
|
-
updates.each do |blocks, attrs|
|
96
|
-
@db[:blk].filter(:hash => blocks.map{|h| htb(h).to_sequel_blob}).update(attrs)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# store transaction +tx+
|
102
|
-
def store_tx(tx)
|
103
|
-
@log.debug { "Storing tx #{tx.hash} (#{tx.to_payload.bytesize} bytes)" }
|
104
|
-
@db.transaction do
|
105
|
-
transaction = @db[:tx][:hash => htb(tx.hash).to_sequel_blob]
|
106
|
-
return transaction[:id] if transaction
|
107
|
-
tx_id = @db[:tx].insert({
|
108
|
-
:hash => htb(tx.hash).to_sequel_blob,
|
109
|
-
:version => tx.ver,
|
110
|
-
:lock_time => tx.lock_time,
|
111
|
-
:coinbase => tx.in.size==1 && tx.in[0].coinbase?,
|
112
|
-
:tx_size => tx.payload.bytesize,
|
113
|
-
})
|
114
|
-
tx.in.each_with_index {|i, idx| store_txin(tx_id, i, idx)}
|
115
|
-
tx.out.each_with_index {|o, idx| store_txout(tx_id, o, idx)}
|
116
|
-
tx_id
|
117
|
-
end
|
118
|
-
rescue
|
119
|
-
@log.warn { "Error storing tx: #{$!}" }
|
120
|
-
end
|
121
|
-
|
122
|
-
# store input +txin+
|
123
|
-
def store_txin(tx_id, txin, idx)
|
124
|
-
@db[:txin].insert({
|
125
|
-
:tx_id => tx_id,
|
126
|
-
:tx_idx => idx,
|
127
|
-
:script_sig => txin.script_sig.to_sequel_blob,
|
128
|
-
:prev_out => txin.prev_out.to_sequel_blob,
|
129
|
-
:prev_out_index => txin.prev_out_index,
|
130
|
-
:sequence => txin.sequence.unpack("I")[0],
|
131
|
-
})
|
132
|
-
end
|
133
|
-
|
134
|
-
# store output +txout+
|
135
|
-
def store_txout(tx_id, txout, idx)
|
136
|
-
script = Bitcoin::Script.new(txout.pk_script)
|
137
|
-
txout_id = @db[:txout].insert({
|
138
|
-
:tx_id => tx_id,
|
139
|
-
:tx_idx => idx,
|
140
|
-
:pk_script => txout.pk_script.to_sequel_blob,
|
141
|
-
:value => txout.value,
|
142
|
-
:type => SCRIPT_TYPES.index(script.type)
|
143
|
-
})
|
144
|
-
if script.is_hash160? || script.is_pubkey?
|
145
|
-
store_addr(txout_id, script.get_hash160)
|
146
|
-
elsif script.is_multisig?
|
147
|
-
script.get_multisig_pubkeys.map do |pubkey|
|
148
|
-
store_addr(txout_id, Bitcoin.hash160(pubkey.unpack("H*")[0]))
|
149
|
-
end
|
150
|
-
end
|
151
|
-
txout_id
|
152
|
-
end
|
153
|
-
|
154
|
-
# store address +hash160+
|
155
|
-
def store_addr(txout_id, hash160)
|
156
|
-
addr = @db[:addr][:hash160 => hash160]
|
157
|
-
addr_id = addr[:id] if addr
|
158
|
-
addr_id ||= @db[:addr].insert({:hash160 => hash160})
|
159
|
-
@db[:addr_txout].insert({:addr_id => addr_id, :txout_id => txout_id})
|
160
|
-
end
|
161
|
-
|
162
|
-
# check if block +blk_hash+ exists
|
163
|
-
def has_block(blk_hash)
|
164
|
-
!!@db[:blk].where(:hash => htb(blk_hash).to_sequel_blob).get(1)
|
165
|
-
end
|
166
|
-
|
167
|
-
# check if transaction +tx_hash+ exists
|
168
|
-
def has_tx(tx_hash)
|
169
|
-
!!@db[:tx].where(:hash => htb(tx_hash).to_sequel_blob).get(1)
|
170
|
-
end
|
171
|
-
|
172
|
-
# get head block (highest block from the MAIN chain)
|
173
|
-
def get_head
|
174
|
-
wrap_block(@db[:blk].filter(:chain => MAIN).order(:depth).last)
|
175
|
-
end
|
176
|
-
|
177
|
-
# get depth of MAIN chain
|
178
|
-
def get_depth
|
179
|
-
return -1 unless get_head
|
180
|
-
@db[:blk][:hash => htb(get_head.hash).to_sequel_blob][:depth]
|
181
|
-
end
|
182
|
-
|
183
|
-
# get block for given +blk_hash+
|
184
|
-
def get_block(blk_hash)
|
185
|
-
wrap_block(@db[:blk][:hash => htb(blk_hash).to_sequel_blob])
|
186
|
-
end
|
187
|
-
|
188
|
-
# get block by given +depth+
|
189
|
-
def get_block_by_depth(depth)
|
190
|
-
wrap_block(@db[:blk][:depth => depth, :chain => MAIN])
|
191
|
-
end
|
192
|
-
|
193
|
-
# get block by given +prev_hash+
|
194
|
-
def get_block_by_prev_hash(prev_hash)
|
195
|
-
wrap_block(@db[:blk][:prev_hash => htb(prev_hash).to_sequel_blob])
|
196
|
-
end
|
197
|
-
|
198
|
-
# get block by given +tx_hash+
|
199
|
-
def get_block_by_tx(tx_hash)
|
200
|
-
tx = @db[:tx][:hash => htb(tx_hash).to_sequel_blob]
|
201
|
-
return nil unless tx
|
202
|
-
parent = @db[:blk_tx][:tx_id => tx[:id]]
|
203
|
-
return nil unless parent
|
204
|
-
wrap_block(@db[:blk][:id => parent[:blk_id]])
|
205
|
-
end
|
206
|
-
|
207
|
-
# get block by given +id+
|
208
|
-
def get_block_by_id(block_id)
|
209
|
-
wrap_block(@db[:blk][:id => block_id])
|
210
|
-
end
|
211
|
-
|
212
|
-
# get transaction for given +tx_hash+
|
213
|
-
def get_tx(tx_hash)
|
214
|
-
wrap_tx(@db[:tx][:hash => htb(tx_hash).to_sequel_blob])
|
215
|
-
end
|
216
|
-
|
217
|
-
# get transaction by given +tx_id+
|
218
|
-
def get_tx_by_id(tx_id)
|
219
|
-
wrap_tx(@db[:tx][:id => tx_id])
|
220
|
-
end
|
221
|
-
|
222
|
-
# get corresponding Models::TxIn for the txout in transaction
|
223
|
-
# +tx_hash+ with index +txout_idx+
|
224
|
-
def get_txin_for_txout(tx_hash, txout_idx)
|
225
|
-
tx_hash = htb(tx_hash).reverse.to_sequel_blob
|
226
|
-
wrap_txin(@db[:txin][:prev_out => tx_hash, :prev_out_index => txout_idx])
|
227
|
-
end
|
228
|
-
|
229
|
-
# get corresponding Models::TxOut for +txin+
|
230
|
-
def get_txout_for_txin(txin)
|
231
|
-
tx = @db[:tx][:hash => txin.prev_out.reverse.to_sequel_blob]
|
232
|
-
return nil unless tx
|
233
|
-
wrap_txout(@db[:txout][:tx_idx => txin.prev_out_index, :tx_id => tx[:id]])
|
234
|
-
end
|
235
|
-
|
236
|
-
# get all Models::TxOut matching given +script+
|
237
|
-
def get_txouts_for_pk_script(script)
|
238
|
-
txouts = @db[:txout].filter(:pk_script => script.to_sequel_blob).order(:id)
|
239
|
-
txouts.map{|txout| wrap_txout(txout)}
|
240
|
-
end
|
241
|
-
|
242
|
-
# get all Models::TxOut matching given +hash160+
|
243
|
-
def get_txouts_for_hash160(hash160, unconfirmed = false)
|
244
|
-
addr = @db[:addr][:hash160 => hash160]
|
245
|
-
return [] unless addr
|
246
|
-
txouts = @db[:addr_txout].where(:addr_id => addr[:id])
|
247
|
-
.map{|t| @db[:txout][:id => t[:txout_id]] }
|
248
|
-
.map{|o| wrap_txout(o) }
|
249
|
-
unless unconfirmed
|
250
|
-
txouts.select!{|o| o.get_tx.get_block.chain == MAIN rescue false }
|
251
|
-
end
|
252
|
-
txouts
|
253
|
-
end
|
254
|
-
|
255
|
-
# get all unconfirmed Models::TxOut
|
256
|
-
def get_unconfirmed_tx
|
257
|
-
@db[:unconfirmed].map{|t| wrap_tx(t)}
|
258
|
-
end
|
259
|
-
|
260
|
-
# wrap given +block+ into Models::Block
|
261
|
-
def wrap_block(block)
|
262
|
-
return nil unless block
|
263
|
-
|
264
|
-
data = {:id => block[:id], :depth => block[:depth], :chain => block[:chain]}
|
265
|
-
blk = Bitcoin::Storage::Models::Block.new(self, data)
|
266
|
-
|
267
|
-
blk.ver = block[:version]
|
268
|
-
blk.prev_block = block[:prev_hash].reverse
|
269
|
-
blk.mrkl_root = block[:mrkl_root].reverse
|
270
|
-
blk.time = block[:time].to_i
|
271
|
-
blk.bits = block[:bits]
|
272
|
-
blk.nonce = block[:nonce]
|
273
|
-
parents = db[:blk_tx].filter(:blk_id => block[:id])
|
274
|
-
.order(:idx) rescue []
|
275
|
-
parents.each do |parent|
|
276
|
-
transaction = db[:tx][:id => parent[:tx_id]]
|
277
|
-
blk.tx << wrap_tx(transaction)
|
278
|
-
end
|
279
|
-
|
280
|
-
blk.recalc_block_hash
|
281
|
-
blk
|
282
|
-
end
|
283
|
-
|
284
|
-
# wrap given +transaction+ into Models::Transaction
|
285
|
-
def wrap_tx(transaction)
|
286
|
-
return nil unless transaction
|
287
|
-
|
288
|
-
parents = @db[:blk_tx].where(:tx_id => transaction[:id])
|
289
|
-
parent = parents.map{|m|@db[:blk][:id => m[:blk_id]]}.sort_by {|b| b[:chain]}.first
|
290
|
-
block_id = parent ? parent[:id] : nil
|
291
|
-
data = {:id => transaction[:id], :blk_id => block_id}
|
292
|
-
tx = Bitcoin::Storage::Models::Tx.new(self, data)
|
293
|
-
|
294
|
-
inputs = db[:txin].filter(:tx_id => transaction[:id]).order(:tx_idx)
|
295
|
-
inputs.each { |i| tx.add_in(wrap_txin(i)) }
|
296
|
-
|
297
|
-
outputs = db[:txout].filter(:tx_id => transaction[:id]).order(:tx_idx)
|
298
|
-
outputs.each { |o| tx.add_out(wrap_txout(o)) }
|
299
|
-
tx.ver = transaction[:version]
|
300
|
-
tx.lock_time = transaction[:lock_time]
|
301
|
-
tx.hash = tx.hash_from_payload(tx.to_payload)
|
302
|
-
tx
|
303
|
-
end
|
304
|
-
|
305
|
-
# wrap given +input+ into Models::TxIn
|
306
|
-
def wrap_txin(input)
|
307
|
-
return nil unless input
|
308
|
-
data = {:id => input[:id], :tx_id => input[:tx_id], :tx_idx => input[:tx_idx]}
|
309
|
-
txin = Bitcoin::Storage::Models::TxIn.new(self, data)
|
310
|
-
txin.prev_out = input[:prev_out]
|
311
|
-
txin.prev_out_index = input[:prev_out_index]
|
312
|
-
txin.script_sig_length = input[:script_sig].bytesize
|
313
|
-
txin.script_sig = input[:script_sig]
|
314
|
-
txin.sequence = [input[:sequence]].pack("I")
|
315
|
-
txin
|
316
|
-
end
|
317
|
-
|
318
|
-
# wrap given +output+ into Models::TxOut
|
319
|
-
def wrap_txout(output)
|
320
|
-
return nil unless output
|
321
|
-
data = {:id => output[:id], :tx_id => output[:tx_id], :tx_idx => output[:tx_idx],
|
322
|
-
:hash160 => output[:hash160], :type => SCRIPT_TYPES[output[:type]]}
|
323
|
-
txout = Bitcoin::Storage::Models::TxOut.new(self, data)
|
324
|
-
txout.value = output[:value]
|
325
|
-
txout.pk_script = output[:pk_script]
|
326
|
-
txout
|
327
|
-
end
|
328
|
-
|
329
|
-
|
330
|
-
def hth(bin); bin.unpack("H*")[0]; end
|
331
|
-
def htb(hex); [hex].pack("H*"); end
|
332
|
-
|
333
|
-
end
|
334
|
-
|
335
|
-
end
|
data/spec/bitcoin/fixtures/0d0affb5964abe804ffe85e53f1dbb9f29e406aa3046e2db04fba240e63c7fdd.json
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"hash":"0d0affb5964abe804ffe85e53f1dbb9f29e406aa3046e2db04fba240e63c7fdd",
|
3
|
-
"ver":1,
|
4
|
-
"vin_sz":1,
|
5
|
-
"vout_sz":2,
|
6
|
-
"lock_time":0,
|
7
|
-
"size":224,
|
8
|
-
"in":[
|
9
|
-
{
|
10
|
-
"prev_out":{
|
11
|
-
"hash":"477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590",
|
12
|
-
"n":0
|
13
|
-
},
|
14
|
-
"scriptSig":"30450220668828280473923647f2fb99450578a18f81e92358d94c933b7033b4370448b8022100cfbce6723163c907b3b86777f0698cc29ea5f89d0fce657a3894afcb1c717da501 033be10bdc7ff38235cf469449147636c4e0e49aacdd0a25af4109cbebd361e0d2"
|
15
|
-
}
|
16
|
-
],
|
17
|
-
"out":[
|
18
|
-
{
|
19
|
-
"value":"0.02900000",
|
20
|
-
"scriptPubKey":"OP_DUP OP_HASH160 2758fcf332b5df477ec6d877d3b72526b827202b OP_EQUALVERIFY OP_CHECKSIG"
|
21
|
-
},
|
22
|
-
{
|
23
|
-
"value":"0.01000000",
|
24
|
-
"scriptPubKey":"51c387bb5c66d1e9d4d054fd96d0844eecf3b664 OP_NOP2 OP_DROP"
|
25
|
-
}
|
26
|
-
]
|
27
|
-
}
|
data/spec/bitcoin/fixtures/477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590.json
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"hash":"477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590",
|
3
|
-
"ver":1,
|
4
|
-
"vin_sz":1,
|
5
|
-
"vout_sz":2,
|
6
|
-
"lock_time":0,
|
7
|
-
"size":224,
|
8
|
-
"in":[
|
9
|
-
{
|
10
|
-
"prev_out":{
|
11
|
-
"hash":"458b9f6cf2d931d72e246d5ca3d7773069430322a0a1a41653d23a5a3cc3e7ea",
|
12
|
-
"n":1
|
13
|
-
},
|
14
|
-
"scriptSig":"304502205b910ff27919bb4b81847e17e19848a8148373b5d84856e8a0798395c1a4df6e022100a9300a11b37b52997726dab17851914151bd647ca053d60a013b8e0ad42d1c6e01 02b2e1e38d1b15170212a852f68045979d790814a139ed57bffba3763f75e18808"
|
15
|
-
}
|
16
|
-
],
|
17
|
-
"out":[
|
18
|
-
{
|
19
|
-
"value":"0.03950000",
|
20
|
-
"scriptPubKey":"OP_DUP OP_HASH160 c39c8d989dfdd7fde0ee80be36113c5abcefcb9c OP_EQUALVERIFY OP_CHECKSIG"
|
21
|
-
},
|
22
|
-
{
|
23
|
-
"value":"0.01000000",
|
24
|
-
"scriptPubKey":"64d63d835705618da2111ca3194f22d067187cf2 OP_NOP2 OP_DROP"
|
25
|
-
}
|
26
|
-
]
|
27
|
-
}
|
data/spec/bitcoin/reorg_spec.rb
DELETED
@@ -1,129 +0,0 @@
|
|
1
|
-
require_relative 'spec_helper'
|
2
|
-
|
3
|
-
include Bitcoin::Builder
|
4
|
-
|
5
|
-
describe "reorg" do
|
6
|
-
|
7
|
-
def create_block prev, store = true
|
8
|
-
block = blk do |b|
|
9
|
-
b.prev_block prev
|
10
|
-
b.tx do |t|
|
11
|
-
t.input {|i| i.coinbase }
|
12
|
-
t.output do |o|
|
13
|
-
o.value 5000000000
|
14
|
-
o.script {|s| s.type :address; s.recipient Bitcoin::Key.generate.addr }
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
@store.store_block(block) if store
|
19
|
-
block
|
20
|
-
end
|
21
|
-
|
22
|
-
def balance addr
|
23
|
-
@store.get_balance(Bitcoin.hash160_from_address(addr))
|
24
|
-
end
|
25
|
-
|
26
|
-
before do
|
27
|
-
Bitcoin.network = :testnet
|
28
|
-
@store = Bitcoin::Storage.sequel(:db => "sqlite:/")
|
29
|
-
@store.log.level = :warn
|
30
|
-
@block0 = Bitcoin::Protocol::Block.new(fixtures_file('testnet/block_0.bin'))
|
31
|
-
@store.store_block(@block0)
|
32
|
-
end
|
33
|
-
|
34
|
-
it "should reorg a single side block" do
|
35
|
-
@store.get_head.should == @block0
|
36
|
-
|
37
|
-
block1 = create_block @block0.hash
|
38
|
-
@store.get_head.should == block1
|
39
|
-
|
40
|
-
block2_0 = create_block block1.hash
|
41
|
-
@store.get_head.should == block2_0
|
42
|
-
|
43
|
-
block2_1 = create_block block1.hash
|
44
|
-
@store.get_head.should == block2_0
|
45
|
-
|
46
|
-
block3 = create_block block2_1.hash
|
47
|
-
@store.get_head.should == block3
|
48
|
-
@store.get_block_by_depth(2).hash.should == block2_1.hash
|
49
|
-
end
|
50
|
-
|
51
|
-
it "should reorg two side blocks" do
|
52
|
-
block1 = create_block @block0.hash
|
53
|
-
@store.get_head.should == block1
|
54
|
-
|
55
|
-
block2_0 = create_block block1.hash
|
56
|
-
@store.get_head.should == block2_0
|
57
|
-
|
58
|
-
block2_1 = create_block block1.hash
|
59
|
-
@store.get_head.should == block2_0
|
60
|
-
|
61
|
-
block3_1 = create_block block2_1.hash
|
62
|
-
@store.get_head.should == block3_1
|
63
|
-
|
64
|
-
block3_0 = create_block block2_0.hash
|
65
|
-
@store.get_head.should == block3_1
|
66
|
-
|
67
|
-
block4 = create_block block3_0.hash
|
68
|
-
@store.get_head.should == block4
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should reconnect orphans" do
|
72
|
-
blocks = [@block0]
|
73
|
-
3.times { blocks << create_block(blocks.last.hash, false) }
|
74
|
-
|
75
|
-
{
|
76
|
-
[0, 1, 2, 3] => [0, 1, 2, 3],
|
77
|
-
[0, 1, 3, 2] => [0, 1, 1, 3],
|
78
|
-
[0, 3, 2, 1] => [0, 0, 0, 3],
|
79
|
-
[0, 3, 1, 2] => [0, 0, 1, 3],
|
80
|
-
[0, 2, 3, 1] => [0, 0, 0, 3],
|
81
|
-
}.each do |order, result|
|
82
|
-
@store.reset
|
83
|
-
order.each_with_index do |n, i|
|
84
|
-
@store.store_block(blocks[n])
|
85
|
-
@store.get_head.should == blocks[result[i]]
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
i = 3; (0..i).to_a.permutation.each do |order|
|
90
|
-
@store.reset
|
91
|
-
order.each {|n| @store.store_block(blocks[n]) }
|
92
|
-
@store.get_head.should == blocks[i]
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should handle existing blocks" do
|
97
|
-
Bitcoin.network = :testnet
|
98
|
-
blocks = [@block0]
|
99
|
-
3.times { blocks << create_block(blocks.last.hash, false) }
|
100
|
-
3.times do
|
101
|
-
@store.store_block(blocks[1]).should == [1, 0]
|
102
|
-
@store.store_block(blocks[2]).should == [2, 0]
|
103
|
-
@store.get_head.should == blocks[2]
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
# see https://bitcointalk.org/index.php?topic=46370.0
|
108
|
-
it "should pass reorg unit tests" do
|
109
|
-
Bitcoin.network = :bitcoin
|
110
|
-
@store.import "./spec/bitcoin/fixtures/reorg/blk_0_to_4.dat"
|
111
|
-
@store.get_depth.should == 4
|
112
|
-
@store.get_head.hash.should =~ /000000002f264d65040/
|
113
|
-
balance("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa").should == 10000000000
|
114
|
-
balance("1NiEGXeURREqqMjCvjCeZn6SwEBZ9AdVet").should == 0
|
115
|
-
balance("1KXFNhNtrRMfgbdiQeuJqnfD7dR4PhniyJ").should == 5000000000
|
116
|
-
balance("1JyMKvPHkrCQd8jQrqTR1rBsAd1VpRhTiE").should == 10000000000
|
117
|
-
@store.import "./spec/bitcoin/fixtures/reorg/blk_3A.dat"
|
118
|
-
@store.import "./spec/bitcoin/fixtures/reorg/blk_4A.dat"
|
119
|
-
@store.get_head.hash.should =~ /000000002f264d65040/
|
120
|
-
@store.import "./spec/bitcoin/fixtures/reorg/blk_5A.dat"
|
121
|
-
@store.get_depth.should == 5
|
122
|
-
@store.get_head.hash.should =~ /00000000195f85184e7/
|
123
|
-
balance("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa").should == 15000000000
|
124
|
-
balance("1NiEGXeURREqqMjCvjCeZn6SwEBZ9AdVet").should == 1000000000
|
125
|
-
balance("1KXFNhNtrRMfgbdiQeuJqnfD7dR4PhniyJ").should == 0
|
126
|
-
balance("1JyMKvPHkrCQd8jQrqTR1rBsAd1VpRhTiE").should == 14000000000
|
127
|
-
end
|
128
|
-
|
129
|
-
end
|