bitcoinrb 0.1.7 → 0.1.8
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/README.md +10 -2
- data/bitcoinrb.gemspec +4 -1
- data/lib/bitcoin/block.rb +8 -0
- data/lib/bitcoin/constants.rb +9 -1
- data/lib/bitcoin/ext_key.rb +7 -3
- data/lib/bitcoin/key.rb +5 -5
- data/lib/bitcoin/message/headers_parser.rb +3 -3
- data/lib/bitcoin/message/inventory.rb +2 -2
- data/lib/bitcoin/message/merkle_block.rb +2 -2
- data/lib/bitcoin/message/reject.rb +2 -2
- data/lib/bitcoin/mnemonic.rb +1 -0
- data/lib/bitcoin/network/connection.rb +6 -3
- data/lib/bitcoin/network/message_handler.rb +3 -3
- data/lib/bitcoin/network/peer.rb +12 -0
- data/lib/bitcoin/network/pool.rb +23 -10
- data/lib/bitcoin/node/cli.rb +12 -0
- data/lib/bitcoin/node/spv.rb +9 -2
- data/lib/bitcoin/opcodes.rb +9 -3
- data/lib/bitcoin/out_point.rb +10 -1
- data/lib/bitcoin/payments/output.pb.rb +20 -0
- data/lib/bitcoin/payments/payment.pb.rb +26 -0
- data/lib/bitcoin/payments/payment_ack.pb.rb +17 -0
- data/lib/bitcoin/payments/payment_details.pb.rb +24 -0
- data/lib/bitcoin/payments/payment_request.pb.rb +79 -0
- data/lib/bitcoin/payments/x509_certificates.pb.rb +18 -0
- data/lib/bitcoin/payments.rb +14 -0
- data/lib/bitcoin/rpc/request_handler.rb +25 -3
- data/lib/bitcoin/script/script.rb +36 -6
- data/lib/bitcoin/script/script_error.rb +4 -0
- data/lib/bitcoin/script/script_interpreter.rb +7 -2
- data/lib/bitcoin/secp256k1/ruby.rb +1 -2
- data/lib/bitcoin/store/spv_chain.rb +1 -1
- data/lib/bitcoin/tx.rb +11 -0
- data/lib/bitcoin/tx_in.rb +10 -1
- data/lib/bitcoin/tx_out.rb +9 -0
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin/wallet/account.rb +2 -2
- data/lib/bitcoin.rb +10 -0
- metadata +28 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 369e8ba42e13931c345e3ebf13023a0b45433d647ea42849028557bfb9036aad
|
4
|
+
data.tar.gz: 460030a26c3cd367706ebb374efda4ad6c7acc3994daa61fd261195076838079
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c741a2415026b02e1760fcd47586fbb8df7219502fbf4223bc6d560b313e765bc916871a4ed87d98f343c48e25f72d9bf49910df17073490a2a96db63304ef43
|
7
|
+
data.tar.gz: 13b72574c4413556d9522bd3825ab818beadf956673f5a3c1ff0d027e736d126176825a7a04bdc4be3d333b96aedb9e9580339a8219937844bd5fd0b9b9d3ba2
|
data/README.md
CHANGED
@@ -19,9 +19,11 @@ Bitcoinrb supports following feature:
|
|
19
19
|
|
20
20
|
## Requirements
|
21
21
|
|
22
|
-
|
22
|
+
### use Node implementation
|
23
23
|
|
24
|
-
|
24
|
+
If you use node features, please install level DB as follows.
|
25
|
+
|
26
|
+
#### install LevelDB
|
25
27
|
|
26
28
|
* for Ubuntu
|
27
29
|
|
@@ -31,6 +33,12 @@ bitcoinrb requires a `leveldb` library.
|
|
31
33
|
|
32
34
|
$ brew install leveldb
|
33
35
|
|
36
|
+
and put `leveldb-ruby` in your Gemfile and run bundle install.
|
37
|
+
|
38
|
+
```
|
39
|
+
gem leveldb-ruby
|
40
|
+
```
|
41
|
+
|
34
42
|
## Installation
|
35
43
|
|
36
44
|
Add this line to your application's Gemfile:
|
data/bitcoinrb.gemspec
CHANGED
@@ -28,11 +28,14 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_runtime_dependency 'thor'
|
29
29
|
spec.add_runtime_dependency 'ffi'
|
30
30
|
spec.add_runtime_dependency 'leb128', '~> 1.0.0'
|
31
|
-
spec.add_runtime_dependency 'leveldb-ruby'
|
32
31
|
spec.add_runtime_dependency 'eventmachine_httpserver'
|
33
32
|
spec.add_runtime_dependency 'rest-client'
|
34
33
|
spec.add_runtime_dependency 'iniparse'
|
35
34
|
spec.add_runtime_dependency 'siphash'
|
35
|
+
spec.add_runtime_dependency 'protobuf'
|
36
|
+
|
37
|
+
# for options
|
38
|
+
spec.add_development_dependency 'leveldb-ruby'
|
36
39
|
|
37
40
|
spec.add_development_dependency 'bundler', '~> 1.11'
|
38
41
|
spec.add_development_dependency 'rake', '~> 10.0'
|
data/lib/bitcoin/block.rb
CHANGED
@@ -9,6 +9,14 @@ module Bitcoin
|
|
9
9
|
@transactions = transactions
|
10
10
|
end
|
11
11
|
|
12
|
+
def self.parse_from_payload(payload)
|
13
|
+
Bitcoin::Message::Block.parse_from_payload(payload).to_block
|
14
|
+
end
|
15
|
+
|
16
|
+
def hash
|
17
|
+
header.hash
|
18
|
+
end
|
19
|
+
|
12
20
|
# calculate block weight
|
13
21
|
def weight
|
14
22
|
stripped_size * (WITNESS_SCALE_FACTOR - 1) + size
|
data/lib/bitcoin/constants.rb
CHANGED
@@ -40,6 +40,7 @@ module Bitcoin
|
|
40
40
|
SCRIPT_VERIFY_MINIMALIF = (1 << 13) # Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector
|
41
41
|
SCRIPT_VERIFY_NULLFAIL = (1 << 14) # Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed
|
42
42
|
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1 << 15) # Public keys in segregated witness scripts must be compressed
|
43
|
+
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1 << 16) # Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
|
43
44
|
|
44
45
|
MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH
|
45
46
|
|
@@ -56,7 +57,10 @@ module Bitcoin
|
|
56
57
|
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY,
|
57
58
|
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY,
|
58
59
|
SCRIPT_VERIFY_LOW_S,
|
59
|
-
|
60
|
+
SCRIPT_VERIFY_WITNESS,
|
61
|
+
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM,
|
62
|
+
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE,
|
63
|
+
SCRIPT_VERIFY_CONST_SCRIPTCODE].inject(SCRIPT_VERIFY_NONE){|flags, f| flags |= f}
|
60
64
|
|
61
65
|
# for script
|
62
66
|
|
@@ -156,6 +160,10 @@ module Bitcoin
|
|
156
160
|
SCRIPT_ERR_WITNESS_UNEXPECTED = 75
|
157
161
|
SCRIPT_ERR_WITNESS_PUBKEYTYPE = 76
|
158
162
|
|
163
|
+
# Constant scriptCode
|
164
|
+
SCRIPT_ERR_OP_CODESEPARATOR = 77
|
165
|
+
SCRIPT_ERR_SIG_FINDANDDELETE = 78
|
166
|
+
|
159
167
|
SCRIPT_ERR_ERROR_COUNT = 80
|
160
168
|
|
161
169
|
ERRCODES_MAP = Hash[*constants.grep(/^SCRIPT_ERR_/).map { |c| [const_get(c), c.to_s] }.flatten]
|
data/lib/bitcoin/ext_key.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Bitcoin
|
2
2
|
|
3
3
|
# Integers modulo the order of the curve(secp256k1)
|
4
|
-
CURVE_ORDER =
|
4
|
+
CURVE_ORDER = ECDSA::Group::Secp256k1.order
|
5
5
|
|
6
6
|
# BIP32 Extended private key
|
7
7
|
class ExtKey
|
@@ -87,7 +87,11 @@ module Bitcoin
|
|
87
87
|
end
|
88
88
|
|
89
89
|
# derive new key
|
90
|
-
|
90
|
+
# @param [Integer] number a child index
|
91
|
+
# @param [Boolean] harden whether hardened key or not. If true, 2^31 is added to +number+.
|
92
|
+
# @return [Bitcoin::ExtKey] derived new key.
|
93
|
+
def derive(number, harden = false)
|
94
|
+
number += 2**31 if harden
|
91
95
|
new_key = ExtKey.new
|
92
96
|
new_key.depth = depth + 1
|
93
97
|
new_key.number = number
|
@@ -102,7 +106,7 @@ module Bitcoin
|
|
102
106
|
raise 'invalid key' if left >= CURVE_ORDER
|
103
107
|
child_priv = (left + key.priv_key.to_i(16)) % CURVE_ORDER
|
104
108
|
raise 'invalid key ' if child_priv >= CURVE_ORDER
|
105
|
-
new_key.key = Bitcoin::Key.new(priv_key: child_priv.
|
109
|
+
new_key.key = Bitcoin::Key.new(priv_key: child_priv.to_even_length_hex.rjust(64, '0'))
|
106
110
|
new_key.chain_code = l[32..-1]
|
107
111
|
new_key.ver = version
|
108
112
|
new_key
|
data/lib/bitcoin/key.rb
CHANGED
@@ -13,7 +13,7 @@ module Bitcoin
|
|
13
13
|
|
14
14
|
MIN_PRIV_KEy_MOD_ORDER = 0x01
|
15
15
|
# Order of secp256k1's generator minus 1.
|
16
|
-
MAX_PRIV_KEY_MOD_ORDER =
|
16
|
+
MAX_PRIV_KEY_MOD_ORDER = ECDSA::Group::Secp256k1.order - 1
|
17
17
|
|
18
18
|
def initialize(priv_key: nil, pubkey: nil, compressed: true)
|
19
19
|
@secp256k1_module = Bitcoin.secp_impl
|
@@ -94,17 +94,17 @@ module Bitcoin
|
|
94
94
|
|
95
95
|
# get pay to pubkey hash address
|
96
96
|
def to_p2pkh
|
97
|
-
Bitcoin::Script.to_p2pkh(hash160).
|
97
|
+
Bitcoin::Script.to_p2pkh(hash160).addresses.first
|
98
98
|
end
|
99
99
|
|
100
100
|
# get pay to witness pubkey hash address
|
101
101
|
def to_p2wpkh
|
102
|
-
Bitcoin::Script.to_p2wpkh(hash160).
|
102
|
+
Bitcoin::Script.to_p2wpkh(hash160).addresses.first
|
103
103
|
end
|
104
104
|
|
105
105
|
# get p2wpkh address nested in p2sh.
|
106
106
|
def to_nested_p2wpkh
|
107
|
-
Bitcoin::Script.to_p2wpkh(hash160).to_p2sh.
|
107
|
+
Bitcoin::Script.to_p2wpkh(hash160).to_p2sh.addresses.first
|
108
108
|
end
|
109
109
|
|
110
110
|
def compressed?
|
@@ -236,7 +236,7 @@ module Bitcoin
|
|
236
236
|
r = sig_array[4...(len_r+4)].pack('C*').bth
|
237
237
|
len_s = sig_array[len_r + 5]
|
238
238
|
s = sig_array[(len_r + 6)...(len_r + 6 + len_s)].pack('C*').bth
|
239
|
-
ECDSA::
|
239
|
+
ECDSA::Signature.new(r.to_i(16), s.to_i(16)).to_der
|
240
240
|
end
|
241
241
|
|
242
242
|
def valid_pubkey?
|
@@ -10,13 +10,13 @@ module Bitcoin
|
|
10
10
|
hashes = []
|
11
11
|
buf = StringIO.new(payload)
|
12
12
|
size.times do
|
13
|
-
hashes << buf.read(32).
|
13
|
+
hashes << buf.read(32).bth
|
14
14
|
end
|
15
|
-
new(ver, hashes, buf.read(32).
|
15
|
+
new(ver, hashes, buf.read(32).bth)
|
16
16
|
end
|
17
17
|
|
18
18
|
def to_payload
|
19
|
-
[version].pack('V') << Bitcoin.pack_var_int(hashes.length) << hashes.map{|h|h.htb
|
19
|
+
[version].pack('V') << Bitcoin.pack_var_int(hashes.length) << hashes.map{|h|h.htb}.join << stop_hash.htb
|
20
20
|
end
|
21
21
|
|
22
22
|
end
|
@@ -27,12 +27,12 @@ module Bitcoin
|
|
27
27
|
def self.parse_from_payload(payload)
|
28
28
|
raise Error, 'invalid inventory size.' if payload.bytesize != 36
|
29
29
|
identifier = payload[0..4].unpack('V').first
|
30
|
-
hash = payload[4..-1].
|
30
|
+
hash = payload[4..-1].bth # internal byte order
|
31
31
|
new(identifier, hash)
|
32
32
|
end
|
33
33
|
|
34
34
|
def to_payload
|
35
|
-
[identifier].pack('V') << hash.htb
|
35
|
+
[identifier].pack('V') << hash.htb
|
36
36
|
end
|
37
37
|
|
38
38
|
def block?
|
@@ -23,7 +23,7 @@ module Bitcoin
|
|
23
23
|
m.tx_count = buf.read(4).unpack('V').first
|
24
24
|
hash_count = Bitcoin.unpack_var_int_from_io(buf)
|
25
25
|
hash_count.times do
|
26
|
-
m.hashes << buf.read(32).
|
26
|
+
m.hashes << buf.read(32).bth
|
27
27
|
end
|
28
28
|
flag_count = Bitcoin.unpack_var_int_from_io(buf)
|
29
29
|
# A sequence of bits packed eight in a byte with the least significant bit first.
|
@@ -33,7 +33,7 @@ module Bitcoin
|
|
33
33
|
|
34
34
|
def to_payload
|
35
35
|
header.to_payload << [tx_count].pack('V') << Bitcoin.pack_var_int(hashes.size) <<
|
36
|
-
hashes.map
|
36
|
+
hashes.map(&:htb).join << Bitcoin.pack_var_int(flags.htb.bytesize) << flags.htb
|
37
37
|
end
|
38
38
|
|
39
39
|
end
|
@@ -32,12 +32,12 @@ module Bitcoin
|
|
32
32
|
message, payload = Bitcoin.unpack_var_string(payload)
|
33
33
|
code, payload = payload.unpack('Ca*')
|
34
34
|
reason, payload = Bitcoin.unpack_var_string(payload)
|
35
|
-
extra = ['tx', 'block'].include?(message) ? payload.
|
35
|
+
extra = ['tx', 'block'].include?(message) ? payload.bth : payload
|
36
36
|
new(message, code, reason, extra)
|
37
37
|
end
|
38
38
|
|
39
39
|
def to_payload
|
40
|
-
e = ['tx', 'block'].include?(message) ? extra.htb
|
40
|
+
e = ['tx', 'block'].include?(message) ? extra.htb : extra
|
41
41
|
Bitcoin.pack_var_string(message) << [code].pack('C') << Bitcoin.pack_var_string(reason) << e
|
42
42
|
end
|
43
43
|
|
data/lib/bitcoin/mnemonic.rb
CHANGED
@@ -52,6 +52,7 @@ module Bitcoin
|
|
52
52
|
# @param [String] passphrase a passphrase which protects mnemonic. the default value is an empty string.
|
53
53
|
# @return [String] seed
|
54
54
|
def to_seed(mnemonic, passphrase: '')
|
55
|
+
to_entropy(mnemonic)
|
55
56
|
OpenSSL::PKCS5.pbkdf2_hmac(mnemonic.join(' ').downcase,
|
56
57
|
'mnemonic' + passphrase, 2048, 64, OpenSSL::Digest::SHA512.new).bth
|
57
58
|
end
|
@@ -24,6 +24,7 @@ module Bitcoin
|
|
24
24
|
@sendheaders = false
|
25
25
|
@attr_accessor = 0
|
26
26
|
@message = ''
|
27
|
+
self.pending_connect_timeout = 5.0
|
27
28
|
end
|
28
29
|
|
29
30
|
def post_init
|
@@ -56,6 +57,11 @@ module Bitcoin
|
|
56
57
|
peer.handle_error(e)
|
57
58
|
end
|
58
59
|
|
60
|
+
def unbind
|
61
|
+
logger.info "unbind. #{addr}"
|
62
|
+
peer.unbind
|
63
|
+
end
|
64
|
+
|
59
65
|
private
|
60
66
|
|
61
67
|
# start handshake
|
@@ -63,9 +69,6 @@ module Bitcoin
|
|
63
69
|
logger.info "begin handshake with #{addr}"
|
64
70
|
send_message(peer.local_version)
|
65
71
|
end
|
66
|
-
|
67
72
|
end
|
68
|
-
|
69
73
|
end
|
70
|
-
|
71
74
|
end
|
@@ -180,8 +180,8 @@ module Bitcoin
|
|
180
180
|
end
|
181
181
|
|
182
182
|
def on_tx(tx)
|
183
|
-
logger.info(
|
184
|
-
|
183
|
+
logger.info("receive tx message. #{tx.build_json}")
|
184
|
+
peer.handle_tx(tx)
|
185
185
|
end
|
186
186
|
|
187
187
|
def on_not_found(not_found)
|
@@ -232,4 +232,4 @@ module Bitcoin
|
|
232
232
|
|
233
233
|
end
|
234
234
|
end
|
235
|
-
end
|
235
|
+
end
|
data/lib/bitcoin/network/peer.rb
CHANGED
@@ -137,9 +137,12 @@ module Bitcoin
|
|
137
137
|
headers.headers.each do |header|
|
138
138
|
break unless header.valid?
|
139
139
|
entry = chain.append_header(header)
|
140
|
+
next unless entry
|
140
141
|
@best_hash = entry.hash
|
141
142
|
@best_height = entry.height
|
142
143
|
end
|
144
|
+
pool.changed
|
145
|
+
pool.notify_observers(:header, {hash: @best_hash, height: @best_height})
|
143
146
|
start_block_header_download if headers.headers.size > 0 # next header download
|
144
147
|
end
|
145
148
|
|
@@ -148,6 +151,10 @@ module Bitcoin
|
|
148
151
|
pool.handle_error(e)
|
149
152
|
end
|
150
153
|
|
154
|
+
def unbind
|
155
|
+
pool.handle_close_peer(self)
|
156
|
+
end
|
157
|
+
|
151
158
|
# close peer connection.
|
152
159
|
def close(msg = '')
|
153
160
|
conn.close(msg)
|
@@ -178,6 +185,11 @@ module Bitcoin
|
|
178
185
|
conn.send_message(getdata)
|
179
186
|
end
|
180
187
|
|
188
|
+
def handle_tx(tx)
|
189
|
+
pool.changed
|
190
|
+
pool.notify_observers(:tx, tx)
|
191
|
+
end
|
192
|
+
|
181
193
|
# send ping message.
|
182
194
|
def send_ping
|
183
195
|
ping = Bitcoin::Message::Ping.new
|
data/lib/bitcoin/network/pool.rb
CHANGED
@@ -11,6 +11,7 @@ module Bitcoin
|
|
11
11
|
|
12
12
|
# peer pool class.
|
13
13
|
class Pool
|
14
|
+
include Observable
|
14
15
|
|
15
16
|
attr_reader :peers # active peers
|
16
17
|
attr_reader :pending_peers # currently connecting peer
|
@@ -39,15 +40,8 @@ module Bitcoin
|
|
39
40
|
logger.debug 'Start connecting other pears.'
|
40
41
|
addr_list = peer_discovery.peers
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
if pending_peers.size < MAX_OUTBOUND_CONNECTIONS
|
45
|
-
peer = Peer.new(ip, port, self, @configuration)
|
46
|
-
pending_peers << peer
|
47
|
-
peer.connect
|
48
|
-
iter.next
|
49
|
-
end
|
50
|
-
end
|
43
|
+
connect(addr_list)
|
44
|
+
|
51
45
|
@started = true
|
52
46
|
end
|
53
47
|
|
@@ -64,6 +58,14 @@ module Bitcoin
|
|
64
58
|
filter_load(peer) if node.wallet
|
65
59
|
end
|
66
60
|
|
61
|
+
def handle_close_peer(peer)
|
62
|
+
return unless started
|
63
|
+
peers.delete(peer)
|
64
|
+
pending_peers.delete(peer)
|
65
|
+
addr_list = peer_discovery.peers - peers.map(&:host) - pending_peers.map(&:host) - [peer.host]
|
66
|
+
connect(addr_list)
|
67
|
+
end
|
68
|
+
|
67
69
|
# terminate peers.
|
68
70
|
def terminate
|
69
71
|
peers.each { |peer| peer.close('terminate') }
|
@@ -112,7 +114,18 @@ module Bitcoin
|
|
112
114
|
id
|
113
115
|
end
|
114
116
|
|
115
|
-
|
117
|
+
def connect(addr_list)
|
118
|
+
port = Bitcoin.chain_params.default_port
|
116
119
|
|
120
|
+
EM::Iterator.new(addr_list, Bitcoin::PARALLEL_THREAD).each do |ip, iter|
|
121
|
+
if pending_peers.size + peers.size < MAX_OUTBOUND_CONNECTIONS
|
122
|
+
peer = Peer.new(ip, port, self, @configuration)
|
123
|
+
pending_peers << peer
|
124
|
+
peer.connect
|
125
|
+
iter.next
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
117
130
|
end
|
118
131
|
end
|
data/lib/bitcoin/node/cli.rb
CHANGED
@@ -30,6 +30,18 @@ module Bitcoin
|
|
30
30
|
request('getpeerinfo')
|
31
31
|
end
|
32
32
|
|
33
|
+
desc 'decoderawtransaction "hexstring"', 'Return a JSON object representing the serialized, hex-encoded transaction.'
|
34
|
+
def decoderawtransaction(hexstring)
|
35
|
+
request('decoderawtransaction', hexstring)
|
36
|
+
end
|
37
|
+
|
38
|
+
desc 'decodescript "hexstring"', 'Decode a hex-encoded script.'
|
39
|
+
def decodescript(hexstring)
|
40
|
+
request('decodescript', hexstring)
|
41
|
+
end
|
42
|
+
|
43
|
+
# wallet cli
|
44
|
+
|
33
45
|
desc 'sendrawtransaction', 'Submits raw transaction (serialized, hex-encoded) to local node and network.'
|
34
46
|
def sendrawtransaction(hex_tx)
|
35
47
|
request('sendrawtransaction', hex_tx)
|
data/lib/bitcoin/node/spv.rb
CHANGED
@@ -60,13 +60,20 @@ module Bitcoin
|
|
60
60
|
pool.filter_clear
|
61
61
|
end
|
62
62
|
|
63
|
+
def add_observer(observer)
|
64
|
+
pool.add_observer(observer)
|
65
|
+
end
|
66
|
+
|
67
|
+
def delete_observer(observer)
|
68
|
+
pool.delete_observer(observer)
|
69
|
+
end
|
70
|
+
|
63
71
|
private
|
64
72
|
|
65
73
|
def setup_filter
|
66
74
|
@bloom = Bitcoin::BloomFilter.create_filter(512, 0.01)
|
67
|
-
wallet.watch_targets.each{|t|bloom.add(t.htb
|
75
|
+
wallet.watch_targets.each{|t|bloom.add(t.htb)} if wallet
|
68
76
|
end
|
69
|
-
|
70
77
|
end
|
71
78
|
end
|
72
79
|
end
|
data/lib/bitcoin/opcodes.rb
CHANGED
@@ -116,8 +116,8 @@ module Bitcoin
|
|
116
116
|
OP_CHECKMULTISIGVERIFY = 0xaf
|
117
117
|
|
118
118
|
# https://en.bitcoin.it/wiki/Script#Locktime
|
119
|
-
OP_NOP2 = OP_CHECKLOCKTIMEVERIFY = 0xb1
|
120
|
-
OP_NOP3 = OP_CHECKSEQUENCEVERIFY = 0xb2
|
119
|
+
OP_NOP2 = OP_CHECKLOCKTIMEVERIFY = OP_CLTV = 0xb1
|
120
|
+
OP_NOP3 = OP_CHECKSEQUENCEVERIFY = OP_CSV = 0xb2
|
121
121
|
|
122
122
|
# https://en.bitcoin.it/wiki/Script#Reserved_words
|
123
123
|
OP_RESERVED = 0x50
|
@@ -136,7 +136,13 @@ module Bitcoin
|
|
136
136
|
OP_NOP9 = 0xb8
|
137
137
|
OP_NOP10 = 0xb9
|
138
138
|
|
139
|
-
|
139
|
+
# https://en.bitcoin.it/wiki/Script#Pseudo-words
|
140
|
+
OP_PUBKEYHASH = 0xfd
|
141
|
+
OP_PUBKEY = 0xfe
|
142
|
+
OP_INVALIDOPCODE = 0xff
|
143
|
+
|
144
|
+
DUPLICATE_KEY = [:OP_NOP2, :OP_NOP3]
|
145
|
+
OPCODES_MAP = Hash[*(constants.grep(/^OP_/) - [:OP_NOP2, :OP_NOP3, :OP_CHECKLOCKTIMEVERIFY, :OP_CHECKSEQUENCEVERIFY]).map { |c| [const_get(c), c.to_s] }.flatten]
|
140
146
|
NAME_MAP = Hash[*constants.grep(/^OP_/).map { |c| [c.to_s, const_get(c)] }.flatten]
|
141
147
|
|
142
148
|
def opcode_to_name(opcode)
|
data/lib/bitcoin/out_point.rb
CHANGED
@@ -14,12 +14,16 @@ module Bitcoin
|
|
14
14
|
@index = index
|
15
15
|
end
|
16
16
|
|
17
|
+
def self.from_txid(txid, index)
|
18
|
+
self.new(txid.rhex, index)
|
19
|
+
end
|
20
|
+
|
17
21
|
def coinbase?
|
18
22
|
hash == COINBASE_HASH && index == COINBASE_INDEX
|
19
23
|
end
|
20
24
|
|
21
25
|
def to_payload
|
22
|
-
[hash.htb
|
26
|
+
[hash.htb, index].pack('a32V')
|
23
27
|
end
|
24
28
|
|
25
29
|
def self.create_coinbase_outpoint
|
@@ -30,6 +34,11 @@ module Bitcoin
|
|
30
34
|
index >= 0 && (!coinbase? && hash != COINBASE_HASH)
|
31
35
|
end
|
32
36
|
|
37
|
+
# convert hash to txid
|
38
|
+
def txid
|
39
|
+
hash.rhex
|
40
|
+
end
|
41
|
+
|
33
42
|
end
|
34
43
|
|
35
44
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module Payments
|
3
|
+
|
4
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#Output
|
5
|
+
class Output < Protobuf::Message
|
6
|
+
|
7
|
+
optional :uint64, :amount, 1, {default: 0}
|
8
|
+
|
9
|
+
required :bytes, :script, 2
|
10
|
+
|
11
|
+
# convert to TxOut object.
|
12
|
+
# @return [Bitcoin::TxOut]
|
13
|
+
def to_tx_out
|
14
|
+
Bitcoin::TxOut.new(value: amount, script_pubkey: Bitcoin::Script.parse_from_payload(script))
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module Payments
|
3
|
+
|
4
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#Payment
|
5
|
+
class Payment < Protobuf::Message
|
6
|
+
|
7
|
+
optional :bytes, :merchant_data, 1
|
8
|
+
|
9
|
+
repeated :bytes, :transactions, 2
|
10
|
+
|
11
|
+
repeated Bitcoin::Payments::Output, :refund_to, 3
|
12
|
+
|
13
|
+
optional :string, :memo, 4
|
14
|
+
|
15
|
+
def self.parse_from_payload(payload)
|
16
|
+
decode(payload)
|
17
|
+
end
|
18
|
+
|
19
|
+
def transactions
|
20
|
+
@values[:transactions].map{|raw_tx|Bitcoin::Tx.parse_from_payload(raw_tx)}
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module Payments
|
3
|
+
|
4
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#PaymentACK
|
5
|
+
class PaymentACK < Protobuf::Message
|
6
|
+
|
7
|
+
required Bitcoin::Payments::Payment, :payment, 1
|
8
|
+
|
9
|
+
optional :string, :memo, 2
|
10
|
+
|
11
|
+
def self.parse_from_payload(payload)
|
12
|
+
decode(payload)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module Payments
|
3
|
+
|
4
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#PaymentDetailsPaymentRequest
|
5
|
+
class PaymentDetails < Protobuf::Message
|
6
|
+
|
7
|
+
optional :string, :network, 1, {default: 'main'}
|
8
|
+
|
9
|
+
repeated Bitcoin::Payments::Output, :outputs, 2
|
10
|
+
|
11
|
+
required :uint64, :time, 3
|
12
|
+
|
13
|
+
optional :uint64, :expires, 4
|
14
|
+
|
15
|
+
optional :string, :memo, 5
|
16
|
+
|
17
|
+
optional :string, :payment_url, 6
|
18
|
+
|
19
|
+
optional :bytes, :merchant_data, 7
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module Payments
|
3
|
+
|
4
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#PaymentDetailsPaymentRequest
|
5
|
+
class PaymentRequest < Protobuf::Message
|
6
|
+
|
7
|
+
optional :uint32, :payment_details_version, 1, {default: 1}
|
8
|
+
|
9
|
+
optional :string, :pki_type, 2, {default: 'none'}
|
10
|
+
|
11
|
+
optional :bytes, :pki_data, 3
|
12
|
+
|
13
|
+
required :bytes, :serialized_payment_details, 4
|
14
|
+
|
15
|
+
optional :bytes, :signature, 5
|
16
|
+
|
17
|
+
def self.parse_from_payload(payload)
|
18
|
+
self.decode(payload)
|
19
|
+
end
|
20
|
+
|
21
|
+
# verify +pki_data+.
|
22
|
+
# @return [Struct] pki information.
|
23
|
+
def verify_pki_data
|
24
|
+
d = Struct.new(:display_name, :merchant_sign_key, :root_auth, :root_auth_name)
|
25
|
+
d
|
26
|
+
end
|
27
|
+
|
28
|
+
# get payment details
|
29
|
+
# @return [Bitcoin::Payments:PaymentDetails]
|
30
|
+
def details
|
31
|
+
PaymentDetails.decode(serialized_payment_details)
|
32
|
+
end
|
33
|
+
|
34
|
+
# get certificates
|
35
|
+
# @return [Array[OpenSSL::X509::Certificate]]
|
36
|
+
def certs
|
37
|
+
return [] unless has_pki?
|
38
|
+
X509Certificates.decode(pki_data).certs
|
39
|
+
end
|
40
|
+
|
41
|
+
# whether exist +pki_data+.
|
42
|
+
def has_pki?
|
43
|
+
pki_type != 'none'
|
44
|
+
end
|
45
|
+
|
46
|
+
# verify signature.
|
47
|
+
def valid_sig?
|
48
|
+
return false unless has_pki?
|
49
|
+
digest = case pki_type
|
50
|
+
when 'x509+sha256'
|
51
|
+
OpenSSL::Digest::SHA256.new
|
52
|
+
when 'x509+sha1'
|
53
|
+
OpenSSL::Digest::SHA1.new
|
54
|
+
else
|
55
|
+
raise "pki_type: #{pki_type} is invalid type."
|
56
|
+
end
|
57
|
+
certs.first.public_key.verify(digest, signature, sig_message)
|
58
|
+
end
|
59
|
+
|
60
|
+
# verify expire time for payment request.
|
61
|
+
def valid_time?
|
62
|
+
expires = details.expires
|
63
|
+
return true if expires == 0
|
64
|
+
Time.now.to_i <= expires
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# Generate data to be signed
|
70
|
+
def sig_message
|
71
|
+
PaymentRequest.new(payment_details_version: payment_details_version,
|
72
|
+
pki_type: pki_type, pki_data: pki_data, signature: '',
|
73
|
+
serialized_payment_details: serialized_payment_details).encode
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module Payments
|
3
|
+
|
4
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#Certificates
|
5
|
+
class X509Certificates < Protobuf::Message
|
6
|
+
|
7
|
+
repeated :bytes, :certificate, 1
|
8
|
+
|
9
|
+
# get certificates
|
10
|
+
# @return [Array[OpenSSL::X509::Certificate]]
|
11
|
+
def certs
|
12
|
+
certificate.map{|v|OpenSSL::X509::Certificate.new(v)}
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'protobuf'
|
2
|
+
|
3
|
+
module Bitcoin
|
4
|
+
module Payments
|
5
|
+
|
6
|
+
autoload :Output, 'bitcoin/payments/output.pb'
|
7
|
+
autoload :Payment, 'bitcoin/payments/payment.pb'
|
8
|
+
autoload :PaymentACK, 'bitcoin/payments/payment_ack.pb'
|
9
|
+
autoload :PaymentDetails, 'bitcoin/payments/payment_details.pb'
|
10
|
+
autoload :PaymentRequest, 'bitcoin/payments/payment_request.pb'
|
11
|
+
autoload :X509Certificates, 'bitcoin/payments/x509_certificates.pb'
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -31,12 +31,12 @@ module Bitcoin
|
|
31
31
|
hash: block_id,
|
32
32
|
height: entry.height,
|
33
33
|
version: entry.header.version,
|
34
|
-
versionHex: entry.header.version.
|
34
|
+
versionHex: entry.header.version.to_even_length_hex,
|
35
35
|
merkleroot: entry.header.merkle_root.rhex,
|
36
36
|
time: entry.header.time,
|
37
37
|
mediantime: node.chain.mtp(block_hash),
|
38
38
|
nonce: entry.header.nonce,
|
39
|
-
bits: entry.header.bits.
|
39
|
+
bits: entry.header.bits.to_even_length_hex,
|
40
40
|
previousblockhash: entry.prev_hash.rhex,
|
41
41
|
nextblockhash: node.chain.next_hash(block_hash).rhex
|
42
42
|
}
|
@@ -53,7 +53,7 @@ module Bitcoin
|
|
53
53
|
id: peer.id,
|
54
54
|
addr: "#{peer.host}:#{peer.port}",
|
55
55
|
addrlocal: local_addr,
|
56
|
-
services: peer.remote_version.services.
|
56
|
+
services: peer.remote_version.services.to_even_length_hex.rjust(16, '0'),
|
57
57
|
relaytxes: peer.remote_version.relay,
|
58
58
|
lastsend: peer.last_send,
|
59
59
|
lastrecv: peer.last_recv,
|
@@ -80,6 +80,28 @@ module Bitcoin
|
|
80
80
|
tx.txid
|
81
81
|
end
|
82
82
|
|
83
|
+
# decode tx data.
|
84
|
+
def decoderawtransaction(hex_tx)
|
85
|
+
begin
|
86
|
+
Bitcoin::Tx.parse_from_payload(hex_tx.htb).to_h
|
87
|
+
rescue Exception
|
88
|
+
raise ArgumentError.new('TX decode failed')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# decode script data.
|
93
|
+
def decodescript(hex_script)
|
94
|
+
begin
|
95
|
+
script = Bitcoin::Script.parse_from_payload(hex_script.htb)
|
96
|
+
h = script.to_h
|
97
|
+
h.delete(:hex)
|
98
|
+
h[:p2sh] = script.to_p2sh.addresses.first unless script.p2sh?
|
99
|
+
h
|
100
|
+
rescue Exception
|
101
|
+
raise ArgumentError.new('Script decode failed')
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
83
105
|
# wallet api
|
84
106
|
|
85
107
|
# create wallet
|
@@ -67,7 +67,7 @@ module Bitcoin
|
|
67
67
|
if opcode
|
68
68
|
script << (v =~ /^\d/ && Opcodes.small_int_to_opcode(v.ord) ? v.ord : opcode)
|
69
69
|
else
|
70
|
-
script << v
|
70
|
+
script << (v =~ /^[0-9]+$/ ? v.to_i : v)
|
71
71
|
end
|
72
72
|
end
|
73
73
|
script
|
@@ -116,10 +116,12 @@ module Bitcoin
|
|
116
116
|
to_payload.bth
|
117
117
|
end
|
118
118
|
|
119
|
-
def
|
120
|
-
return p2pkh_addr if p2pkh?
|
121
|
-
return p2sh_addr if p2sh?
|
122
|
-
return bech32_addr if witness_program?
|
119
|
+
def addresses
|
120
|
+
return [p2pkh_addr] if p2pkh?
|
121
|
+
return [p2sh_addr] if p2sh?
|
122
|
+
return [bech32_addr] if witness_program?
|
123
|
+
return get_multisig_pubkeys.map{|pubkey| Bitcoin::Key.new(pubkey: pubkey.bth).to_p2pkh} if multisig?
|
124
|
+
[]
|
123
125
|
end
|
124
126
|
|
125
127
|
# check whether standard script.
|
@@ -272,7 +274,16 @@ module Bitcoin
|
|
272
274
|
when String
|
273
275
|
if c.pushdata?
|
274
276
|
v = Opcodes.opcode_to_small_int(c.ord)
|
275
|
-
|
277
|
+
if v
|
278
|
+
v
|
279
|
+
else
|
280
|
+
data = c.pushed_data
|
281
|
+
if data.bytesize <= 4
|
282
|
+
Script.decode_number(data.bth) # for scriptnum
|
283
|
+
else
|
284
|
+
data.bth
|
285
|
+
end
|
286
|
+
end
|
276
287
|
else
|
277
288
|
Opcodes.opcode_to_name(c.ord)
|
278
289
|
end
|
@@ -409,6 +420,25 @@ module Bitcoin
|
|
409
420
|
chunks == other.chunks
|
410
421
|
end
|
411
422
|
|
423
|
+
def type
|
424
|
+
return 'pubkeyhash' if p2pkh?
|
425
|
+
return 'scripthash' if p2sh?
|
426
|
+
return 'multisig' if multisig?
|
427
|
+
return 'witness_v0_keyhash' if p2wpkh?
|
428
|
+
return 'witness_v0_scripthash' if p2wsh?
|
429
|
+
'nonstandard'
|
430
|
+
end
|
431
|
+
|
432
|
+
def to_h
|
433
|
+
h = {asm: to_s, hex: to_payload.bth, type: type}
|
434
|
+
addrs = addresses
|
435
|
+
unless addrs.empty?
|
436
|
+
h[:req_sigs] = multisig? ? Bitcoin::Opcodes.opcode_to_small_int(chunks[0].bth.to_i(16)) :addrs.size
|
437
|
+
h[:addresses] = addrs
|
438
|
+
end
|
439
|
+
h
|
440
|
+
end
|
441
|
+
|
412
442
|
private
|
413
443
|
|
414
444
|
# generate p2pkh address. if script dose not p2pkh, return nil.
|
@@ -92,6 +92,10 @@ module Bitcoin
|
|
92
92
|
'Witness provided for non-witness script'
|
93
93
|
when SCRIPT_ERR_WITNESS_PUBKEYTYPE
|
94
94
|
'Using non-compressed keys in segwit'
|
95
|
+
when SCRIPT_ERR_OP_CODESEPARATOR
|
96
|
+
'Using OP_CODESEPARATOR in non-witness scrip'
|
97
|
+
when SCRIPT_ERR_SIG_FINDANDDELETE
|
98
|
+
'Signature is found in scriptCode'
|
95
99
|
when SCRIPT_ERR_UNKNOWN_ERROR, SCRIPT_ERR_ERROR_COUNT
|
96
100
|
'unknown error'
|
97
101
|
else
|
@@ -156,6 +156,7 @@ module Bitcoin
|
|
156
156
|
return set_error(SCRIPT_ERR_OP_COUNT)
|
157
157
|
end
|
158
158
|
return set_error(SCRIPT_ERR_DISABLED_OPCODE) if DISABLE_OPCODES.include?(opcode)
|
159
|
+
return set_error(SCRIPT_ERR_OP_CODESEPARATOR) if opcode == OP_CODESEPARATOR && sig_version == :base && flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE)
|
159
160
|
next unless (need_exec || (OP_IF <= opcode && opcode <= OP_ENDIF))
|
160
161
|
small_int = Opcodes.opcode_to_small_int(opcode)
|
161
162
|
if small_int && opcode != OP_0
|
@@ -396,7 +397,9 @@ module Bitcoin
|
|
396
397
|
|
397
398
|
subscript = script.subscript(last_code_separator_index..-1)
|
398
399
|
if sig_version == :base
|
399
|
-
|
400
|
+
tmp = subscript.find_and_delete(Script.new << sig)
|
401
|
+
return set_error(SCRIPT_ERR_SIG_FINDANDDELETE) if flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE) && tmp != subscript
|
402
|
+
subscript = tmp
|
400
403
|
end
|
401
404
|
|
402
405
|
return false if !check_pubkey_encoding(pubkey, sig_version) || !check_signature_encoding(sig) # error already set.
|
@@ -445,7 +448,9 @@ module Bitcoin
|
|
445
448
|
|
446
449
|
if sig_version == :base
|
447
450
|
sigs.each do |sig|
|
448
|
-
|
451
|
+
tmp = subscript.find_and_delete(Script.new << sig)
|
452
|
+
return set_error(SCRIPT_ERR_SIG_FINDANDDELETE) if flag?(SCRIPT_VERIFY_CONST_SCRIPTCODE) && tmp != subscript
|
453
|
+
subscript = tmp
|
449
454
|
end
|
450
455
|
end
|
451
456
|
|
@@ -47,9 +47,8 @@ module Bitcoin
|
|
47
47
|
|
48
48
|
return nil if s.zero?
|
49
49
|
|
50
|
-
signature = ECDSA::Signature.new(r, s)
|
50
|
+
signature = ECDSA::Signature.new(r, s).to_der
|
51
51
|
public_key = Bitcoin::Key.new(priv_key: privkey.bth).pubkey
|
52
|
-
signature = ECDSA::Format::SignatureDerString.encode(signature) # signature with DER format
|
53
52
|
raise 'Creation of signature failed.' unless Bitcoin::Secp256k1::Ruby.verify_sig(data, signature, public_key)
|
54
53
|
signature
|
55
54
|
end
|
@@ -43,7 +43,7 @@ module Bitcoin
|
|
43
43
|
# @param [Bitcoin::BlockHeader] header a block header.
|
44
44
|
# @return [Bitcoin::Store::ChainEntry] appended block header entry.
|
45
45
|
def append_header(header)
|
46
|
-
logger.info("append header #{header.
|
46
|
+
logger.info("append header #{header.block_id}")
|
47
47
|
raise "this header is invalid. #{header.hash}" unless header.valid?
|
48
48
|
best_block = latest_block
|
49
49
|
current_height = best_block.height
|
data/lib/bitcoin/tx.rb
CHANGED
@@ -109,6 +109,10 @@ module Bitcoin
|
|
109
109
|
!inputs.find { |i| !i.script_witness.empty? }.nil?
|
110
110
|
end
|
111
111
|
|
112
|
+
def ==(other)
|
113
|
+
hash == other.hash
|
114
|
+
end
|
115
|
+
|
112
116
|
# serialize tx with old tx format
|
113
117
|
def serialize_old_format
|
114
118
|
buf = [version].pack('V')
|
@@ -219,6 +223,13 @@ module Bitcoin
|
|
219
223
|
end
|
220
224
|
end
|
221
225
|
|
226
|
+
def to_h
|
227
|
+
{
|
228
|
+
txid: txid, hash: witness_hash.rhex, version: version, size: size, vsize: vsize, locktime: lock_time,
|
229
|
+
vin: inputs.map(&:to_h), vout: outputs.map.with_index{|tx_out, index| tx_out.to_h.merge({n: index})}
|
230
|
+
}
|
231
|
+
end
|
232
|
+
|
222
233
|
private
|
223
234
|
|
224
235
|
# generate sighash with legacy format
|
data/lib/bitcoin/tx_in.rb
CHANGED
@@ -35,7 +35,7 @@ module Bitcoin
|
|
35
35
|
buf = payload.is_a?(String) ? StringIO.new(payload) : payload
|
36
36
|
i = new
|
37
37
|
hash, index = buf.read(36).unpack('a32V')
|
38
|
-
i.out_point = OutPoint.new(hash.
|
38
|
+
i.out_point = OutPoint.new(hash.bth, index)
|
39
39
|
sig_length = Bitcoin.unpack_var_int_from_io(buf)
|
40
40
|
sig = buf.read(sig_length)
|
41
41
|
if i.coinbase?
|
@@ -62,6 +62,15 @@ module Bitcoin
|
|
62
62
|
!script_witness.empty?
|
63
63
|
end
|
64
64
|
|
65
|
+
def to_h
|
66
|
+
sig = script_sig.to_h
|
67
|
+
sig.delete(:type)
|
68
|
+
h = {txid: out_point.txid, vout: out_point.index, script_sig: sig }
|
69
|
+
h[:txinwitness] = script_witness.stack.map(&:bth) if has_witness?
|
70
|
+
h[:sequence] = sequence
|
71
|
+
h
|
72
|
+
end
|
73
|
+
|
65
74
|
end
|
66
75
|
|
67
76
|
end
|
data/lib/bitcoin/tx_out.rb
CHANGED
data/lib/bitcoin/version.rb
CHANGED
@@ -53,7 +53,7 @@ module Bitcoin
|
|
53
53
|
end
|
54
54
|
|
55
55
|
# create new receive key
|
56
|
-
# @return [Bitcoin::
|
56
|
+
# @return [Bitcoin::ExtPubkey]
|
57
57
|
def create_receive
|
58
58
|
@receive_depth += 1
|
59
59
|
save
|
@@ -61,7 +61,7 @@ module Bitcoin
|
|
61
61
|
end
|
62
62
|
|
63
63
|
# create new change key
|
64
|
-
#
|
64
|
+
# @return [Bitcoin::ExtPubkey]
|
65
65
|
def create_change
|
66
66
|
@change_depth += 1
|
67
67
|
save
|
data/lib/bitcoin.rb
CHANGED
@@ -8,6 +8,7 @@ require 'securerandom'
|
|
8
8
|
require 'json'
|
9
9
|
require 'bech32'
|
10
10
|
require 'ffi'
|
11
|
+
require 'observer'
|
11
12
|
require 'tmpdir'
|
12
13
|
require_relative 'openassets'
|
13
14
|
|
@@ -44,6 +45,7 @@ module Bitcoin
|
|
44
45
|
autoload :RPC, 'bitcoin/rpc'
|
45
46
|
autoload :Wallet, 'bitcoin/wallet'
|
46
47
|
autoload :BloomFilter, 'bitcoin/bloom_filter'
|
48
|
+
autoload :Payments, 'bitcoin/payments'
|
47
49
|
|
48
50
|
require_relative 'bitcoin/constants'
|
49
51
|
|
@@ -180,4 +182,12 @@ module Bitcoin
|
|
180
182
|
hex.rjust((hex.length / 2.0).ceil * 2, '0')
|
181
183
|
end
|
182
184
|
end
|
185
|
+
|
186
|
+
class ::ECDSA::Signature
|
187
|
+
# convert signature to der string.
|
188
|
+
def to_der
|
189
|
+
ECDSA::Format::SignatureDerString.encode(self)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
183
193
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitcoinrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- azuchi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ecdsa
|
@@ -123,7 +123,7 @@ dependencies:
|
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: 1.0.0
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: eventmachine_httpserver
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - ">="
|
@@ -137,7 +137,7 @@ dependencies:
|
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
140
|
+
name: rest-client
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - ">="
|
@@ -151,7 +151,7 @@ dependencies:
|
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
154
|
+
name: iniparse
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
157
|
- - ">="
|
@@ -165,7 +165,7 @@ dependencies:
|
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
|
-
name:
|
168
|
+
name: siphash
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
170
170
|
requirements:
|
171
171
|
- - ">="
|
@@ -179,7 +179,7 @@ dependencies:
|
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0'
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
|
-
name:
|
182
|
+
name: protobuf
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
185
|
- - ">="
|
@@ -192,6 +192,20 @@ dependencies:
|
|
192
192
|
- - ">="
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: leveldb-ruby
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
195
209
|
- !ruby/object:Gem::Dependency
|
196
210
|
name: bundler
|
197
211
|
requirement: !ruby/object:Gem::Requirement
|
@@ -344,6 +358,13 @@ files:
|
|
344
358
|
- lib/bitcoin/node/spv.rb
|
345
359
|
- lib/bitcoin/opcodes.rb
|
346
360
|
- lib/bitcoin/out_point.rb
|
361
|
+
- lib/bitcoin/payments.rb
|
362
|
+
- lib/bitcoin/payments/output.pb.rb
|
363
|
+
- lib/bitcoin/payments/payment.pb.rb
|
364
|
+
- lib/bitcoin/payments/payment_ack.pb.rb
|
365
|
+
- lib/bitcoin/payments/payment_details.pb.rb
|
366
|
+
- lib/bitcoin/payments/payment_request.pb.rb
|
367
|
+
- lib/bitcoin/payments/x509_certificates.pb.rb
|
347
368
|
- lib/bitcoin/rpc.rb
|
348
369
|
- lib/bitcoin/rpc/http_server.rb
|
349
370
|
- lib/bitcoin/rpc/request_handler.rb
|