bitcoin-ruby 0.0.6 → 0.0.7
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.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/.travis.yml +2 -7
- data/COPYING +1 -1
- data/Gemfile +2 -6
- data/Gemfile.lock +34 -0
- data/README.rdoc +16 -68
- data/Rakefile +3 -6
- data/bin/bitcoin_shell +0 -1
- data/{concept-examples/blockchain-pow.rb → examples/concept-blockchain-pow.rb} +0 -0
- data/lib/bitcoin.rb +350 -296
- data/lib/bitcoin/builder.rb +3 -1
- data/lib/bitcoin/connection.rb +2 -1
- data/lib/bitcoin/contracthash.rb +76 -0
- data/lib/bitcoin/dogecoin.rb +97 -0
- data/lib/bitcoin/ffi/bitcoinconsensus.rb +74 -0
- data/lib/bitcoin/ffi/openssl.rb +98 -2
- data/lib/bitcoin/ffi/secp256k1.rb +144 -0
- data/lib/bitcoin/key.rb +12 -2
- data/lib/bitcoin/logger.rb +3 -12
- data/lib/bitcoin/protocol/block.rb +3 -9
- data/lib/bitcoin/protocol/parser.rb +6 -2
- data/lib/bitcoin/protocol/tx.rb +44 -13
- data/lib/bitcoin/protocol/txin.rb +4 -2
- data/lib/bitcoin/protocol/txout.rb +2 -2
- data/lib/bitcoin/script.rb +212 -37
- data/lib/bitcoin/trezor/mnemonic.rb +130 -0
- data/lib/bitcoin/version.rb +1 -1
- data/spec/bitcoin/bitcoin_spec.rb +32 -3
- data/spec/bitcoin/builder_spec.rb +18 -0
- data/spec/bitcoin/contracthash_spec.rb +45 -0
- data/spec/bitcoin/dogecoin_spec.rb +176 -0
- data/spec/bitcoin/ffi_openssl.rb +45 -0
- data/spec/bitcoin/fixtures/156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a.json +24 -0
- data/spec/bitcoin/fixtures/8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c.json +24 -0
- data/spec/bitcoin/fixtures/coinbase-toshi.json +33 -0
- data/spec/bitcoin/fixtures/coinbase.json +24 -0
- data/spec/bitcoin/fixtures/dogecoin-block-60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-01-toshi.json +46 -0
- data/spec/bitcoin/fixtures/rawtx-02-toshi.json +46 -0
- data/spec/bitcoin/fixtures/rawtx-03-toshi.json +73 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-6f0bbdd4e71a8af4305018d738184df32dbb6f27284fdebd5b56d16947f7c181.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-a7c9b06e275e8674cc19a5f7d3e557c72c6d93576e635b33212dbe08ab7cdb60.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-testnet-f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5.bin +0 -0
- data/spec/bitcoin/protocol/block_spec.rb +0 -22
- data/spec/bitcoin/protocol/tx_spec.rb +145 -2
- data/spec/bitcoin/script/script_spec.rb +282 -0
- data/spec/bitcoin/secp256k1_spec.rb +48 -0
- data/spec/bitcoin/spec_helper.rb +0 -51
- data/spec/bitcoin/trezor/mnemonic_spec.rb +161 -0
- metadata +48 -98
- data/bin/bitcoin_dns_seed +0 -130
- data/bin/bitcoin_gui +0 -80
- data/bin/bitcoin_node +0 -153
- data/bin/bitcoin_node_cli +0 -81
- data/bin/bitcoin_wallet +0 -402
- data/doc/CONFIG.rdoc +0 -66
- data/doc/EXAMPLES.rdoc +0 -13
- data/doc/NAMECOIN.rdoc +0 -34
- data/doc/NODE.rdoc +0 -225
- data/doc/STORAGE.rdoc +0 -33
- data/doc/WALLET.rdoc +0 -102
- data/examples/balance.rb +0 -66
- data/examples/forwarder.rb +0 -73
- data/examples/index_nhash.rb +0 -24
- data/examples/reindex_p2sh_addrs.rb +0 -44
- data/examples/relay_tx.rb +0 -22
- data/examples/verify_tx.rb +0 -57
- data/lib/bitcoin/config.rb +0 -58
- data/lib/bitcoin/gui/addr_view.rb +0 -44
- data/lib/bitcoin/gui/bitcoin-ruby.png +0 -0
- data/lib/bitcoin/gui/bitcoin-ruby.svg +0 -80
- data/lib/bitcoin/gui/conn_view.rb +0 -38
- data/lib/bitcoin/gui/connection.rb +0 -70
- data/lib/bitcoin/gui/em_gtk.rb +0 -30
- data/lib/bitcoin/gui/gui.builder +0 -1643
- data/lib/bitcoin/gui/gui.rb +0 -292
- data/lib/bitcoin/gui/helpers.rb +0 -115
- data/lib/bitcoin/gui/tree_view.rb +0 -84
- data/lib/bitcoin/gui/tx_view.rb +0 -69
- data/lib/bitcoin/namecoin.rb +0 -280
- data/lib/bitcoin/network/command_client.rb +0 -104
- data/lib/bitcoin/network/command_handler.rb +0 -570
- data/lib/bitcoin/network/connection_handler.rb +0 -387
- data/lib/bitcoin/network/node.rb +0 -565
- data/lib/bitcoin/storage/dummy/dummy_store.rb +0 -179
- data/lib/bitcoin/storage/models.rb +0 -171
- data/lib/bitcoin/storage/sequel/migrations.rb +0 -99
- data/lib/bitcoin/storage/sequel/migrations/001_base_schema.rb +0 -52
- data/lib/bitcoin/storage/sequel/migrations/002_tx.rb +0 -45
- data/lib/bitcoin/storage/sequel/migrations/003_change_txin_script_sig_to_blob.rb +0 -18
- data/lib/bitcoin/storage/sequel/migrations/004_change_txin_prev_out_to_blob.rb +0 -18
- data/lib/bitcoin/storage/sequel/migrations/005_change_tx_hash_to_bytea.rb +0 -14
- data/lib/bitcoin/storage/sequel/migrations/006_add_tx_nhash.rb +0 -31
- data/lib/bitcoin/storage/sequel/migrations/007_add_prev_out_index_index.rb +0 -16
- data/lib/bitcoin/storage/sequel/migrations/008_add_txin_p2sh_type.rb +0 -31
- data/lib/bitcoin/storage/sequel/migrations/009_add_addrs_type.rb +0 -56
- data/lib/bitcoin/storage/sequel/sequel_store.rb +0 -551
- data/lib/bitcoin/storage/storage.rb +0 -517
- data/lib/bitcoin/storage/utxo/migrations/001_base_schema.rb +0 -52
- data/lib/bitcoin/storage/utxo/migrations/002_utxo.rb +0 -18
- data/lib/bitcoin/storage/utxo/migrations/003_update_indices.rb +0 -14
- data/lib/bitcoin/storage/utxo/migrations/004_add_addrs_type.rb +0 -14
- data/lib/bitcoin/storage/utxo/utxo_store.rb +0 -374
- data/lib/bitcoin/validation.rb +0 -400
- data/lib/bitcoin/wallet/coinselector.rb +0 -33
- data/lib/bitcoin/wallet/keygenerator.rb +0 -77
- data/lib/bitcoin/wallet/keystore.rb +0 -207
- data/lib/bitcoin/wallet/txdp.rb +0 -118
- data/lib/bitcoin/wallet/wallet.rb +0 -281
- data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.bin +0 -0
- data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.json +0 -43
- data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.bin +0 -0
- data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.json +0 -67
- data/spec/bitcoin/namecoin_spec.rb +0 -182
- data/spec/bitcoin/node/command_api_spec.rb +0 -663
- data/spec/bitcoin/storage/models_spec.rb +0 -104
- data/spec/bitcoin/storage/reorg_spec.rb +0 -236
- data/spec/bitcoin/storage/storage_spec.rb +0 -387
- data/spec/bitcoin/storage/validation_spec.rb +0 -300
- data/spec/bitcoin/wallet/coinselector_spec.rb +0 -38
- data/spec/bitcoin/wallet/keygenerator_spec.rb +0 -69
- data/spec/bitcoin/wallet/keystore_spec.rb +0 -190
- data/spec/bitcoin/wallet/txdp_spec.rb +0 -76
- data/spec/bitcoin/wallet/wallet_spec.rb +0 -238
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
Sequel.migration do
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
up do
|
|
5
|
-
|
|
6
|
-
@log.info { "Running migration #{__FILE__}" }
|
|
7
|
-
|
|
8
|
-
binary = adapter_scheme == :postgres ? :bytea : :varchar
|
|
9
|
-
|
|
10
|
-
alter_table :schema_info do
|
|
11
|
-
add_column :magic, :varchar # network magic-head
|
|
12
|
-
add_column :backend, :varchar # storage backend
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
next if tables.include?(:blk)
|
|
16
|
-
|
|
17
|
-
create_table :blk do
|
|
18
|
-
primary_key :id
|
|
19
|
-
column :hash, binary, :null => false, :unique => true, :index => true
|
|
20
|
-
column :depth, :int, :null => false, :index => true
|
|
21
|
-
column :version, :bigint, :null => false
|
|
22
|
-
column :prev_hash, binary, :null => false, :index => true
|
|
23
|
-
column :mrkl_root, binary, :null => false
|
|
24
|
-
column :time, :bigint, :null => false
|
|
25
|
-
column :bits, :bigint, :null => false
|
|
26
|
-
column :nonce, :bigint, :null => false
|
|
27
|
-
column :blk_size, :int, :null => false
|
|
28
|
-
column :chain, :int, :null => false
|
|
29
|
-
column :work, binary, :index => true
|
|
30
|
-
column :aux_pow, binary
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
create_table :addr do
|
|
34
|
-
primary_key :id
|
|
35
|
-
column :hash160, String, :null => false, :index => true
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
create_table :addr_txout do
|
|
39
|
-
column :addr_id, :int, :null => false, :index => true
|
|
40
|
-
column :txout_id, :int, :null => false, :index => true
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
create_table :names do
|
|
44
|
-
column :txout_id, :int, :null => false, :index => true
|
|
45
|
-
column :hash, binary, :index => true
|
|
46
|
-
column :name, binary, :index => true
|
|
47
|
-
column :value, binary
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
Sequel.migration do
|
|
2
|
-
|
|
3
|
-
up do
|
|
4
|
-
|
|
5
|
-
@log.info { "Running migration #{__FILE__}" }
|
|
6
|
-
|
|
7
|
-
create_table :utxo do
|
|
8
|
-
primary_key :id
|
|
9
|
-
column :tx_hash, String, null: false, index: true
|
|
10
|
-
column :tx_idx, :int, null: false, index: true
|
|
11
|
-
column :blk_id, :int, null: false, index: true
|
|
12
|
-
column :pk_script, (@db.adapter_scheme == :postgres ? :bytea : :blob), null: false
|
|
13
|
-
column :value, :bigint, null: false, index: true
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
end
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
Sequel.migration do
|
|
2
|
-
up do
|
|
3
|
-
@log.info { "Running migration #{__FILE__}" }
|
|
4
|
-
|
|
5
|
-
alter_table :utxo do
|
|
6
|
-
# This is used when deleting spent uxto rows
|
|
7
|
-
add_index([:tx_hash, :tx_idx])
|
|
8
|
-
|
|
9
|
-
# These don't seem to be necessary
|
|
10
|
-
drop_index :tx_idx
|
|
11
|
-
drop_index :value
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Add column addr.type and correct the type for all p2sh addresses
|
|
2
|
-
|
|
3
|
-
Sequel.migration do
|
|
4
|
-
|
|
5
|
-
up do
|
|
6
|
-
|
|
7
|
-
@log.info { "Running migration #{__FILE__}" }
|
|
8
|
-
|
|
9
|
-
add_column :addr, :type, :int, default: 0, null: false
|
|
10
|
-
add_index :addr, [:hash160, :type]
|
|
11
|
-
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
end
|
|
@@ -1,374 +0,0 @@
|
|
|
1
|
-
Bitcoin.require_dependency :sequel, message:
|
|
2
|
-
"Note: You will also need an adapter for your database like sqlite3, mysql2, postgresql"
|
|
3
|
-
|
|
4
|
-
module Bitcoin::Storage::Backends
|
|
5
|
-
|
|
6
|
-
# Storage backend using Sequel to connect to arbitrary SQL databases.
|
|
7
|
-
# Inherits from StoreBase and implements its interface.
|
|
8
|
-
class UtxoStore < SequelStoreBase
|
|
9
|
-
|
|
10
|
-
# possible script types
|
|
11
|
-
SCRIPT_TYPES = [:unknown, :pubkey, :hash160, :multisig, :p2sh]
|
|
12
|
-
if Bitcoin.namecoin?
|
|
13
|
-
[:name_new, :name_firstupdate, :name_update].each {|n| SCRIPT_TYPES << n }
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# sequel database connection
|
|
17
|
-
attr_accessor :db
|
|
18
|
-
|
|
19
|
-
DEFAULT_CONFIG = {
|
|
20
|
-
# cache head block; it is only updated when new block comes in,
|
|
21
|
-
# so this should only be used by the store receiving new blocks.
|
|
22
|
-
cache_head: false,
|
|
23
|
-
# cache this many utxo records before syncing to disk.
|
|
24
|
-
# this should only be enabled during initial sync, because
|
|
25
|
-
# with it the store cannot reorg properly.
|
|
26
|
-
utxo_cache: 250,
|
|
27
|
-
# cache this many blocks.
|
|
28
|
-
# NOTE: this is also the maximum number of blocks the store can reorg.
|
|
29
|
-
block_cache: 120,
|
|
30
|
-
# keep an index of utxos for all addresses, not just the ones
|
|
31
|
-
# we are explicitly told about.
|
|
32
|
-
index_all_addrs: false
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
# create sequel store with given +config+
|
|
36
|
-
def initialize config, *args
|
|
37
|
-
super config, *args
|
|
38
|
-
@spent_outs, @new_outs, @watched_addrs = [], [], []
|
|
39
|
-
@deleted_utxos, @tx_cache, @block_cache = {}, {}, {}
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# connect to database
|
|
43
|
-
def connect
|
|
44
|
-
super
|
|
45
|
-
load_watched_addrs
|
|
46
|
-
# rescan
|
|
47
|
-
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# reset database; delete all data
|
|
51
|
-
def reset
|
|
52
|
-
[:blk, :utxo, :addr, :addr_txout].each {|table| @db[table].delete }
|
|
53
|
-
@head = nil
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# persist given block +blk+ to storage.
|
|
57
|
-
def persist_block blk, chain, depth, prev_work = 0
|
|
58
|
-
load_watched_addrs
|
|
59
|
-
@db.transaction do
|
|
60
|
-
attrs = {
|
|
61
|
-
:hash => blk.hash.htb.blob,
|
|
62
|
-
:depth => depth,
|
|
63
|
-
:chain => chain,
|
|
64
|
-
:version => blk.ver,
|
|
65
|
-
:prev_hash => blk.prev_block.reverse.blob,
|
|
66
|
-
:mrkl_root => blk.mrkl_root.reverse.blob,
|
|
67
|
-
:time => blk.time,
|
|
68
|
-
:bits => blk.bits,
|
|
69
|
-
:nonce => blk.nonce,
|
|
70
|
-
:blk_size => blk.payload.bytesize,
|
|
71
|
-
:work => (prev_work + blk.block_work).to_s
|
|
72
|
-
}
|
|
73
|
-
existing = @db[:blk].filter(:hash => blk.hash.htb.blob)
|
|
74
|
-
if existing.any?
|
|
75
|
-
existing.update attrs
|
|
76
|
-
block_id = existing.first[:id]
|
|
77
|
-
else
|
|
78
|
-
block_id = @db[:blk].insert(attrs)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
if @config[:block_cache] > 0
|
|
82
|
-
@block_cache.shift if @block_cache.size > @config[:block_cache]
|
|
83
|
-
@deleted_utxos.shift if @deleted_utxos.size > @config[:block_cache]
|
|
84
|
-
@block_cache[blk.hash] = blk
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
if chain == MAIN
|
|
88
|
-
persist_transactions(blk.tx, block_id, depth)
|
|
89
|
-
@tx_cache = {}
|
|
90
|
-
@head = wrap_block(attrs.merge(id: block_id)) if chain == MAIN
|
|
91
|
-
end
|
|
92
|
-
return depth, chain
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def persist_transactions txs, block_id, depth
|
|
97
|
-
txs.each.with_index do |tx, tx_blk_idx|
|
|
98
|
-
tx.in.each.with_index do |txin, txin_tx_idx|
|
|
99
|
-
next if txin.coinbase?
|
|
100
|
-
size = @new_outs.size
|
|
101
|
-
@new_outs.delete_if {|o| o[0][:tx_hash] == txin.prev_out.reverse.hth &&
|
|
102
|
-
o[0][:tx_idx] == txin.prev_out_index }
|
|
103
|
-
@spent_outs << {
|
|
104
|
-
tx_hash: txin.prev_out.reverse.hth.to_sequel_blob,
|
|
105
|
-
tx_idx: txin.prev_out_index } if @new_outs.size == size
|
|
106
|
-
end
|
|
107
|
-
tx.out.each.with_index do |txout, txout_tx_idx|
|
|
108
|
-
_, a, n = *parse_script(txout, txout_tx_idx, tx.hash, txout_tx_idx)
|
|
109
|
-
@new_outs << [{
|
|
110
|
-
:tx_hash => tx.hash.blob,
|
|
111
|
-
:tx_idx => txout_tx_idx,
|
|
112
|
-
:blk_id => block_id,
|
|
113
|
-
:pk_script => txout.pk_script.blob,
|
|
114
|
-
:value => txout.value },
|
|
115
|
-
@config[:index_all_addrs] ? a : a.select {|a| @watched_addrs.include?(a[1]) },
|
|
116
|
-
Bitcoin.namecoin? ? n : [] ]
|
|
117
|
-
end
|
|
118
|
-
flush_spent_outs(depth) if @spent_outs.size > @config[:utxo_cache]
|
|
119
|
-
flush_new_outs(depth) if @new_outs.size > @config[:utxo_cache]
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def reorg new_side, new_main
|
|
124
|
-
new_side.each do |block_hash|
|
|
125
|
-
raise "trying to remove non-head block!" unless get_head.hash == block_hash
|
|
126
|
-
depth = get_depth
|
|
127
|
-
blk = @db[:blk][hash: block_hash.htb.blob]
|
|
128
|
-
delete_utxos = @db[:utxo].where(blk_id: blk[:id])
|
|
129
|
-
@db[:addr_txout].where("txout_id IN ?", delete_utxos.map{|o|o[:id]}).delete
|
|
130
|
-
|
|
131
|
-
delete_utxos.delete
|
|
132
|
-
(@deleted_utxos[depth] || []).each do |utxo|
|
|
133
|
-
utxo[:pk_script] = utxo[:pk_script].to_sequel_blob
|
|
134
|
-
utxo_id = @db[:utxo].insert(utxo)
|
|
135
|
-
addrs = Bitcoin::Script.new(utxo[:pk_script]).get_addresses
|
|
136
|
-
addrs.each do |addr|
|
|
137
|
-
hash160 = Bitcoin.hash160_from_address(addr)
|
|
138
|
-
store_addr(utxo_id, hash160)
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
@db[:blk].where(id: blk[:id]).update(chain: SIDE)
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
new_main.each do |block_hash|
|
|
146
|
-
block = @db[:blk][hash: block_hash.htb.blob]
|
|
147
|
-
blk = @block_cache[block_hash]
|
|
148
|
-
persist_transactions(blk.tx, block[:id], block[:depth])
|
|
149
|
-
@db[:blk].where(id: block[:id]).update(chain: MAIN)
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def flush_spent_outs depth
|
|
154
|
-
log.time "flushed #{@spent_outs.size} spent txouts in %.4fs" do
|
|
155
|
-
if @spent_outs.any?
|
|
156
|
-
@spent_outs.each_slice(250) do |slice|
|
|
157
|
-
if @db.adapter_scheme == :postgres
|
|
158
|
-
condition = slice.map {|o| "(tx_hash = '#{o[:tx_hash]}' AND tx_idx = #{o[:tx_idx]})" }.join(" OR ")
|
|
159
|
-
else
|
|
160
|
-
condition = slice.map {|o| "(tx_hash = X'#{o[:tx_hash].hth}' AND tx_idx = #{o[:tx_idx]})" }.join(" OR ")
|
|
161
|
-
end
|
|
162
|
-
@db["DELETE FROM addr_txout WHERE EXISTS
|
|
163
|
-
(SELECT 1 FROM utxo WHERE
|
|
164
|
-
utxo.id = addr_txout.txout_id AND (#{condition}));"].all
|
|
165
|
-
@db["DELETE FROM utxo WHERE #{condition};"].first
|
|
166
|
-
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
@spent_outs = []
|
|
170
|
-
end
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def flush_new_outs depth
|
|
174
|
-
log.time "flushed #{@new_outs.size} new txouts in %.4fs" do
|
|
175
|
-
new_utxo_ids = @db[:utxo].insert_multiple(@new_outs.map{|o|o[0]})
|
|
176
|
-
@new_outs.each.with_index do |d, idx|
|
|
177
|
-
d[1].each do |i, hash160|
|
|
178
|
-
next unless i && hash160
|
|
179
|
-
store_addr(new_utxo_ids[idx], hash160)
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
@new_outs.each.with_index do |d, idx|
|
|
184
|
-
d[2].each do |i, script|
|
|
185
|
-
next unless i && script
|
|
186
|
-
store_name(script, new_utxo_ids[idx])
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
@new_outs = []
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
# store hash160 and type of +addr+
|
|
194
|
-
def store_addr(txout_id, addr)
|
|
195
|
-
hash160 = Bitcoin.hash160_from_address(addr)
|
|
196
|
-
type = ADDRESS_TYPES.index(Bitcoin.address_type(addr))
|
|
197
|
-
|
|
198
|
-
addr = @db[:addr][hash160: hash160, type: type]
|
|
199
|
-
addr_id = addr[:id] if addr
|
|
200
|
-
addr_id ||= @db[:addr].insert(hash160: hash160, type: type)
|
|
201
|
-
|
|
202
|
-
@db[:addr_txout].insert(addr_id: addr_id, txout_id: txout_id)
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
def add_watched_address address
|
|
206
|
-
hash160 = Bitcoin.hash160_from_address(address)
|
|
207
|
-
@db[:addr].insert(hash160: hash160) unless @db[:addr][hash160: hash160]
|
|
208
|
-
@watched_addrs << hash160 unless @watched_addrs.include?(hash160)
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
def load_watched_addrs
|
|
212
|
-
@watched_addrs = @db[:addr].all.map{|a| a[:hash160] } unless @config[:index_all_addrs]
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
def rescan
|
|
216
|
-
load_watched_addrs
|
|
217
|
-
@rescan_lock ||= Monitor.new
|
|
218
|
-
@rescan_lock.synchronize do
|
|
219
|
-
log.info { "Rescanning #{@db[:utxo].count} utxos for #{@watched_addrs.size} addrs" }
|
|
220
|
-
count = @db[:utxo].count; n = 100_000
|
|
221
|
-
@db[:utxo].order(:id).each_slice(n).with_index do |slice, index|
|
|
222
|
-
log.debug { "rescan progress: %.2f%" % (100.0 / count * (index*n)) }
|
|
223
|
-
slice.each do |utxo|
|
|
224
|
-
next if utxo[:pk_script].bytesize >= 10_000
|
|
225
|
-
hash160 = Bitcoin::Script.new(utxo[:pk_script]).get_hash160
|
|
226
|
-
if @config[:index_all_addrs] || @watched_addrs.include?(hash160)
|
|
227
|
-
log.info { "Found utxo for address #{Bitcoin.hash160_to_address(hash160)}: " +
|
|
228
|
-
"#{utxo[:tx_hash][0..8]}:#{utxo[:tx_idx]} (#{utxo[:value]})" }
|
|
229
|
-
addr = @db[:addr][hash160: hash160]
|
|
230
|
-
addr_utxo = {addr_id: addr[:id], txout_id: utxo[:id]}
|
|
231
|
-
@db[:addr_txout].insert(addr_utxo) unless @db[:addr_txout][addr_utxo]
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
end
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
# check if block +blk_hash+ exists
|
|
239
|
-
def has_block(blk_hash)
|
|
240
|
-
!!@db[:blk].where(:hash => blk_hash.htb.blob).get(1)
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
# check if transaction +tx_hash+ exists
|
|
244
|
-
def has_tx(tx_hash)
|
|
245
|
-
!!@db[:utxo].where(:tx_hash => tx_hash.blob).get(1)
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
# get head block (highest block from the MAIN chain)
|
|
249
|
-
def get_head
|
|
250
|
-
(@config[:cache_head] && @head) ? @head :
|
|
251
|
-
@head = wrap_block(@db[:blk].filter(:chain => MAIN).order(:depth).last)
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
# get depth of MAIN chain
|
|
255
|
-
def get_depth
|
|
256
|
-
return -1 unless get_head
|
|
257
|
-
get_head.depth
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
# get block for given +blk_hash+
|
|
261
|
-
def get_block(blk_hash)
|
|
262
|
-
wrap_block(@db[:blk][:hash => blk_hash.htb.blob])
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
# get block by given +depth+
|
|
266
|
-
def get_block_by_depth(depth)
|
|
267
|
-
wrap_block(@db[:blk][:depth => depth, :chain => MAIN])
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
# get block by given +prev_hash+
|
|
271
|
-
def get_block_by_prev_hash(prev_hash)
|
|
272
|
-
wrap_block(@db[:blk][:prev_hash => prev_hash.htb.blob, :chain => MAIN])
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
# get block by given +tx_hash+
|
|
276
|
-
def get_block_by_tx(tx_hash)
|
|
277
|
-
block_id = @db[:utxo][tx_hash: tx_hash.blob][:blk_id]
|
|
278
|
-
get_block_by_id(block_id)
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
# get block by given +id+
|
|
282
|
-
def get_block_by_id(block_id)
|
|
283
|
-
wrap_block(@db[:blk][:id => block_id])
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
# get transaction for given +tx_hash+
|
|
287
|
-
def get_tx(tx_hash)
|
|
288
|
-
@tx_cache[tx_hash] ||= wrap_tx(tx_hash)
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
# get transaction by given +tx_id+
|
|
292
|
-
def get_tx_by_id(tx_id)
|
|
293
|
-
get_tx(tx_id)
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
def get_txout_by_id(id)
|
|
297
|
-
wrap_txout(@db[:utxo][id: id])
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
# get corresponding Models::TxOut for +txin+
|
|
301
|
-
def get_txout_for_txin(txin)
|
|
302
|
-
wrap_txout(@db[:utxo][tx_hash: txin.prev_out.reverse.hth.blob, tx_idx: txin.prev_out_index])
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
# get the next input that references given output
|
|
306
|
-
# we only store unspent outputs, so it's always nil
|
|
307
|
-
def get_txin_for_txout(tx_hash, tx_idx)
|
|
308
|
-
nil
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
# get all Models::TxOut matching given +script+
|
|
312
|
-
def get_txouts_for_pk_script(script)
|
|
313
|
-
utxos = @db[:utxo].filter(pk_script: script.blob).order(:blk_id)
|
|
314
|
-
utxos.map {|utxo| wrap_txout(utxo) }
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
# get all Models::TxOut matching given +hash160+
|
|
318
|
-
def get_txouts_for_hash160(hash160, type = :hash160, unconfirmed = false)
|
|
319
|
-
addr = @db[:addr][hash160: hash160, type: ADDRESS_TYPES.index(type)]
|
|
320
|
-
return [] unless addr
|
|
321
|
-
@db[:addr_txout].where(addr_id: addr[:id]).map {|ao| wrap_txout(@db[:utxo][id: ao[:txout_id]]) }.compact
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
# wrap given +block+ into Models::Block
|
|
325
|
-
def wrap_block(block)
|
|
326
|
-
return nil unless block
|
|
327
|
-
|
|
328
|
-
data = {:id => block[:id], :depth => block[:depth], :chain => block[:chain],
|
|
329
|
-
:work => block[:work].to_i, :hash => block[:hash].hth}
|
|
330
|
-
blk = Bitcoin::Storage::Models::Block.new(self, data)
|
|
331
|
-
|
|
332
|
-
blk.ver = block[:version]
|
|
333
|
-
blk.prev_block = block[:prev_hash].reverse
|
|
334
|
-
blk.mrkl_root = block[:mrkl_root].reverse
|
|
335
|
-
blk.time = block[:time].to_i
|
|
336
|
-
blk.bits = block[:bits]
|
|
337
|
-
blk.nonce = block[:nonce]
|
|
338
|
-
|
|
339
|
-
if cached = @block_cache[block[:hash].hth]
|
|
340
|
-
blk.tx = cached.tx
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
blk.recalc_block_hash
|
|
344
|
-
blk
|
|
345
|
-
end
|
|
346
|
-
|
|
347
|
-
# wrap given +transaction+ into Models::Transaction
|
|
348
|
-
def wrap_tx(tx_hash)
|
|
349
|
-
utxos = @db[:utxo].where(tx_hash: tx_hash.blob)
|
|
350
|
-
return nil unless utxos.any?
|
|
351
|
-
data = { blk_id: utxos.first[:blk_id], id: tx_hash }
|
|
352
|
-
tx = Bitcoin::Storage::Models::Tx.new(self, data)
|
|
353
|
-
tx.hash = tx_hash # utxos.first[:tx_hash].hth
|
|
354
|
-
utxos.each {|u| tx.out[u[:tx_idx]] = wrap_txout(u) }
|
|
355
|
-
return tx
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
# wrap given +output+ into Models::TxOut
|
|
359
|
-
def wrap_txout(utxo)
|
|
360
|
-
return nil unless utxo
|
|
361
|
-
data = {id: utxo[:id], tx_id: utxo[:tx_hash], tx_idx: utxo[:tx_idx]}
|
|
362
|
-
txout = Bitcoin::Storage::Models::TxOut.new(self, data)
|
|
363
|
-
txout.value = utxo[:value]
|
|
364
|
-
txout.pk_script = utxo[:pk_script]
|
|
365
|
-
txout
|
|
366
|
-
end
|
|
367
|
-
|
|
368
|
-
def check_consistency(*args)
|
|
369
|
-
log.warn { "Utxo store doesn't support consistency check" }
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
end
|
|
373
|
-
|
|
374
|
-
end
|