bitcoin-ruby 0.0.1 → 0.0.2
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 +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
|