bitcoinrb 0.1.7 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|