bitcoinrb 1.12.0 → 1.12.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -1
  3. data/bitcoinrb.gemspec +1 -6
  4. data/lib/bitcoin/bip324/fs_chacha20.rb +3 -5
  5. data/lib/bitcoin/bip324/fs_chacha_poly1305.rb +19 -17
  6. data/lib/bitcoin/bip324.rb +1 -1
  7. data/lib/bitcoin/descriptor/expression.rb +2 -2
  8. data/lib/bitcoin/descriptor/sp.rb +219 -0
  9. data/lib/bitcoin/descriptor.rb +20 -0
  10. data/lib/bitcoin/ext_key.rb +3 -3
  11. data/lib/bitcoin/message/ping.rb +4 -2
  12. data/lib/bitcoin/message/version.rb +1 -1
  13. data/lib/bitcoin/message_sign.rb +98 -38
  14. data/lib/bitcoin/rpc.rb +0 -2
  15. data/lib/bitcoin/silent_payment/output.rb +46 -0
  16. data/lib/bitcoin/silent_payment.rb +113 -12
  17. data/lib/bitcoin/util.rb +2 -2
  18. data/lib/bitcoin/version.rb +1 -1
  19. data/lib/bitcoin.rb +0 -6
  20. metadata +18 -108
  21. data/exe/bitcoinrb-cli +0 -5
  22. data/exe/bitcoinrbd +0 -46
  23. data/lib/bitcoin/network/connection.rb +0 -73
  24. data/lib/bitcoin/network/message_handler.rb +0 -243
  25. data/lib/bitcoin/network/peer.rb +0 -228
  26. data/lib/bitcoin/network/peer_discovery.rb +0 -42
  27. data/lib/bitcoin/network/pool.rb +0 -135
  28. data/lib/bitcoin/network.rb +0 -13
  29. data/lib/bitcoin/node/cli.rb +0 -122
  30. data/lib/bitcoin/node/configuration.rb +0 -40
  31. data/lib/bitcoin/node/spv.rb +0 -87
  32. data/lib/bitcoin/node.rb +0 -7
  33. data/lib/bitcoin/rpc/http_server.rb +0 -84
  34. data/lib/bitcoin/rpc/request_handler.rb +0 -150
  35. data/lib/bitcoin/store/chain_entry.rb +0 -68
  36. data/lib/bitcoin/store/db/level_db.rb +0 -98
  37. data/lib/bitcoin/store/db.rb +0 -9
  38. data/lib/bitcoin/store/spv_chain.rb +0 -101
  39. data/lib/bitcoin/store/utxo_db.rb +0 -226
  40. data/lib/bitcoin/store.rb +0 -12
@@ -1,101 +0,0 @@
1
- module Bitcoin
2
-
3
- module Store
4
-
5
- KEY_PREFIX = {
6
- entry: 'e', # key: block hash, value: Bitcoin::Store::ChainEntry payload
7
- height: 'h', # key: block height, value: block hash.
8
- best: 'B', # value: best block hash.
9
- next: 'n' # key: block hash, value: A hash of the next block of the specified hash
10
- }
11
-
12
- class SPVChain
13
-
14
- attr_reader :db
15
- attr_reader :logger
16
-
17
- def initialize(db = Bitcoin::Store::DB::LevelDB.new)
18
- @db = db # TODO multiple db switch
19
- @logger = Bitcoin::Logger.create(:debug)
20
- initialize_block
21
- end
22
-
23
- # get latest block in the store.
24
- # @return[Bitcoin::Store::ChainEntry]
25
- def latest_block
26
- hash = db.best_hash
27
- return nil unless hash
28
- find_entry_by_hash(hash)
29
- end
30
-
31
- # find block entry with the specified height.
32
- def find_entry_by_height(height)
33
- find_entry_by_hash(db.get_hash_from_height(height))
34
- end
35
-
36
- # find block entry with the specified hash
37
- def find_entry_by_hash(hash)
38
- payload = db.get_entry_payload_from_hash(hash)
39
- return nil unless payload
40
- ChainEntry.parse_from_payload(payload)
41
- end
42
-
43
- # append block header to chain.
44
- # @param [Bitcoin::BlockHeader] header a block header.
45
- # @return [Bitcoin::Store::ChainEntry] appended block header entry.
46
- def append_header(header)
47
- logger.info("append header #{header.block_id}")
48
- raise "this header is invalid. #{header.block_hash}" unless header.valid?
49
- best_block = latest_block
50
- current_height = best_block.height
51
- if best_block.block_hash == header.prev_hash
52
- entry = Bitcoin::Store::ChainEntry.new(header, current_height + 1)
53
- db.save_entry(entry)
54
- entry
55
- else
56
- unless find_entry_by_hash(header.block_hash)
57
- # TODO implements recovery process
58
- raise "header's previous hash(#{header.prev_hash}) does not match current best block's(#{best_block.block_hash})."
59
- end
60
- end
61
- end
62
-
63
- # get next block hash for specified +hash+
64
- # @param [String] hash the block hash(little endian)
65
- # @return [String] the next block hash. If it does not exist yet, return nil.
66
- def next_hash(hash)
67
- db.next_hash(hash)
68
- end
69
-
70
- # get median time past for specified block +hash+
71
- # @param [String] hash the block hash.
72
- # @return [Integer] the median time past value.
73
- def mtp(hash)
74
- time = []
75
- Bitcoin::MEDIAN_TIME_SPAN.times do
76
- entry = find_entry_by_hash(hash)
77
- break unless entry
78
-
79
- time << entry.header.time
80
- hash = entry.header.prev_hash
81
- end
82
- time.sort!
83
- time[time.size / 2]
84
- end
85
-
86
- private
87
-
88
- # if database is empty, put genesis block.
89
- def initialize_block
90
- unless latest_block
91
- block = Bitcoin.chain_params.genesis_block
92
- genesis = ChainEntry.new(block.header, 0)
93
- db.save_entry(genesis)
94
- end
95
- end
96
-
97
- end
98
-
99
- end
100
-
101
- end
@@ -1,226 +0,0 @@
1
- require 'leveldb-native'
2
-
3
- module Bitcoin
4
- module Store
5
- class UtxoDB
6
-
7
- KEY_PREFIX = {
8
- out_point: 'o', # key: out_point(tx_hash and index), value: Utxo
9
- script: 's', # key: script_pubkey and out_point(tx_hash and index), value: Utxo
10
- height: 'h', # key: block_height and out_point, value: Utxo
11
- tx_hash: 't', # key: tx_hash of transaction, value: [block_height, tx_index]
12
- block: 'b', # key: block_height and tx_index, value: tx_hash
13
- tx_payload: 'p', # key: tx_hash, value: Tx
14
- }
15
-
16
- attr_reader :level_db, :logger
17
-
18
- def initialize(path = "#{Bitcoin.base_dir}/db/utxo")
19
- FileUtils.mkdir_p(path)
20
- @level_db = ::LevelDBNative::DB.new(path)
21
- @logger = Bitcoin::Logger.create(:debug)
22
- end
23
-
24
- def close
25
- level_db.close
26
- end
27
-
28
- # Save payload of a transaction into db
29
- #
30
- # @param [String] tx_hash
31
- # @param [String] tx_payload
32
- def save_tx(tx_hash, tx_payload)
33
- logger.info("UtxoDB#save_tx:#{[tx_hash, tx_payload]}")
34
- level_db.batch do
35
- # tx_hash -> [block_height, tx_index]
36
- key = KEY_PREFIX[:tx_payload] + tx_hash
37
- level_db.put(key, tx_payload)
38
- end
39
- end
40
-
41
- # Save tx position (block height and index in the block) into db
42
- # When node receives `header` message, node should call save_tx_position to store block height and its index.
43
- #
44
- # @param [String] tx_hash
45
- # @param [Integer] block_height
46
- # @param [Integer] tx_index
47
- def save_tx_position(tx_hash, block_height, tx_index)
48
- logger.info("UtxoDB#save_tx_position:#{[tx_hash, block_height, tx_index]}")
49
- level_db.batch do
50
- # tx_hash -> [block_height, tx_index]
51
- key = KEY_PREFIX[:tx_hash] + tx_hash
52
- level_db.put(key, [block_height, tx_index].pack('N2').bth)
53
-
54
- # block_hash and tx_index -> tx_hash
55
- key = KEY_PREFIX[:block] + [block_height, tx_index].pack('N2').bth
56
- level_db.put(key, tx_hash)
57
- end
58
- end
59
-
60
- # Save utxo into db
61
- #
62
- # @param [Bitcoin::OutPoint] out_point
63
- # @param [Double] value
64
- # @param [Bitcoin::Script] script_pubkey
65
- # @param [Integer] block_height
66
- def save_utxo(out_point, value, script_pubkey, block_height=nil)
67
- logger.info("UtxoDB#save_utxo:#{[out_point, value, script_pubkey, block_height]}")
68
- level_db.batch do
69
- utxo = Bitcoin::Wallet::Utxo.new(out_point.tx_hash, out_point.index, value, script_pubkey, block_height)
70
- payload = utxo.to_payload
71
-
72
- # out_point
73
- key = KEY_PREFIX[:out_point] + out_point.to_hex
74
- return if level_db.contains?(key)
75
- level_db.put(key, payload)
76
-
77
- # script_pubkey
78
- if script_pubkey
79
- key = KEY_PREFIX[:script] + script_pubkey.to_hex + out_point.to_hex
80
- level_db.put(key, payload)
81
- end
82
-
83
- # height
84
- unless block_height.nil?
85
- key = KEY_PREFIX[:height] + [block_height].pack('N').bth + out_point.to_hex
86
- level_db.put(key, payload)
87
- end
88
-
89
- utxo
90
- end
91
- end
92
-
93
- # Get transaction stored via save_tx and save_tx_position
94
- #
95
- # @param [string] tx_hash
96
- # @return [block_height, tx_index, tx_payload]
97
- def get_tx(tx_hash)
98
- key = KEY_PREFIX[:tx_hash] + tx_hash
99
- return [] unless level_db.contains?(key)
100
- block_height, tx_index = level_db.get(key).htb.unpack('N2')
101
- key = KEY_PREFIX[:tx_payload] + tx_hash
102
- tx_payload = level_db.get(key)
103
- [block_height, tx_index, tx_payload]
104
- end
105
-
106
- # Delete utxo from db
107
- #
108
- # @param [Bitcoin::Outpoint] out_point
109
- # @return [Bitcoin::Wallet::Utxo]
110
- def delete_utxo(out_point)
111
- level_db.batch do
112
- # [:out_point]
113
- key = KEY_PREFIX[:out_point] + out_point.to_hex
114
- return unless level_db.contains?(key)
115
- utxo = Bitcoin::Wallet::Utxo.parse_from_payload(level_db.get(key))
116
- level_db.delete(key)
117
-
118
- # [:script]
119
- if utxo.script_pubkey
120
- key = KEY_PREFIX[:script] + utxo.script_pubkey.to_hex + out_point.to_hex
121
- level_db.delete(key)
122
- end
123
-
124
- if utxo.block_height
125
- # [:height]
126
- key = KEY_PREFIX[:height] + [utxo.block_height].pack('N').bth + out_point.to_hex
127
- level_db.delete(key)
128
-
129
- # [:block]
130
- key = KEY_PREFIX[:block] + [utxo.block_height, utxo.index].pack('N2').bth
131
- level_db.delete(key)
132
- end
133
-
134
- # handles both [:tx_hash] and [:tx_payload]
135
- if utxo.tx_hash
136
- key = KEY_PREFIX[:tx_hash] + utxo.tx_hash
137
- level_db.delete(key)
138
-
139
- key = KEY_PREFIX[:tx_payload] + utxo.tx_hash
140
- level_db.delete(key)
141
- end
142
-
143
- utxo
144
- end
145
- end
146
-
147
- # Get utxo of the specified out point
148
- #
149
- # @param [Bitcoin::Outpoint] out_point
150
- # @return [Bitcoin::Wallet::Utxo]
151
- def get_utxo(out_point)
152
- level_db.batch do
153
- key = KEY_PREFIX[:out_point] + out_point.to_hex
154
- return unless level_db.contains?(key)
155
- return Bitcoin::Wallet::Utxo.parse_from_payload(level_db.get(key))
156
- end
157
- end
158
-
159
- # return [Bitcoin::Wallet::Utxo ...]
160
- def list_unspent(current_block_height: 9999999, min: 0, max: 9999999, addresses: nil)
161
- if addresses
162
- list_unspent_by_addresses(current_block_height, min: min, max: max, addresses: addresses)
163
- else
164
- list_unspent_by_block_height(current_block_height, min: min, max: max)
165
- end
166
- end
167
-
168
- # @param [Bitcoin::Wallet::Account]
169
- # return [Bitcoin::Wallet::Utxo ...]
170
- def list_unspent_in_account(account, current_block_height: 9999999, min: 0, max: 9999999)
171
- return [] unless account
172
-
173
- script_pubkeys = case account.purpose
174
- when Bitcoin::Wallet::Account::PURPOSE_TYPE[:legacy]
175
- account.watch_targets.map { |t| Bitcoin::Script.to_p2pkh(t).to_hex }
176
- when Bitcoin::Wallet::Account::PURPOSE_TYPE[:nested_witness]
177
- account.watch_targets.map { |t| Bitcoin::Script.to_p2wpkh(t).to_p2sh.to_hex }
178
- when Bitcoin::Wallet::Account::PURPOSE_TYPE[:native_segwit]
179
- account.watch_targets.map { |t| Bitcoin::Script.to_p2wpkh(t).to_hex }
180
- end
181
- list_unspent_by_script_pubkeys(current_block_height, min: min, max: max, script_pubkeys: script_pubkeys)
182
- end
183
-
184
- # @param [Bitcoin::Wallet::Account]
185
- # return [Bitcoin::Wallet::Utxo ...]
186
- def get_balance(account, current_block_height: 9999999, min: 0, max: 9999999)
187
- list_unspent_in_account(account, current_block_height: current_block_height, min: min, max: max).sum { |u| u.value }
188
- end
189
-
190
- private
191
-
192
- def utxos_between(from, to)
193
- level_db.each(from: from, to: to).map { |k, v| Bitcoin::Wallet::Utxo.parse_from_payload(v) }
194
- end
195
-
196
- class ::Array
197
- def with_height(min, max)
198
- select { |u| u.block_height >= min && u.block_height <= max }
199
- end
200
- end
201
-
202
- def list_unspent_by_block_height(current_block_height, min: 0, max: 9999999)
203
- max_height = [current_block_height - min, 0].max
204
- min_height = [current_block_height - max, 0].max
205
- from = KEY_PREFIX[:height] + [min_height].pack('N').bth + '000000000000000000000000000000000000000000000000000000000000000000000000'
206
- to = KEY_PREFIX[:height] + [max_height].pack('N').bth + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
207
- utxos_between(from, to)
208
- end
209
-
210
- def list_unspent_by_addresses(current_block_height, min: 0, max: 9999999, addresses: [])
211
- script_pubkeys = addresses.map { |a| Bitcoin::Script.parse_from_addr(a).to_hex }
212
- list_unspent_by_script_pubkeys(current_block_height, min: min, max: max, script_pubkeys: script_pubkeys)
213
- end
214
-
215
- def list_unspent_by_script_pubkeys(current_block_height, min: 0, max: 9999999, script_pubkeys: [])
216
- max_height = current_block_height - min
217
- min_height = current_block_height - max
218
- script_pubkeys.map do |key|
219
- from = KEY_PREFIX[:script] + key + '000000000000000000000000000000000000000000000000000000000000000000000000'
220
- to = KEY_PREFIX[:script] + key + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
221
- utxos_between(from, to).with_height(min_height, max_height)
222
- end.flatten
223
- end
224
- end
225
- end
226
- end
data/lib/bitcoin/store.rb DELETED
@@ -1,12 +0,0 @@
1
- require 'leveldb-native'
2
-
3
- module Bitcoin
4
- module Store
5
-
6
- autoload :DB, 'bitcoin/store/db'
7
- autoload :SPVChain, 'bitcoin/store/spv_chain'
8
- autoload :ChainEntry, 'bitcoin/store/chain_entry'
9
- autoload :UtxoDB, 'bitcoin/store/utxo_db'
10
-
11
- end
12
- end