bitcoinrb 0.1.5 → 0.1.6
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 +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +1 -0
- data/README.md +40 -1
- data/bitcoinrb.gemspec +1 -0
- data/lib/bitcoin/base58.rb +2 -4
- data/lib/bitcoin/bloom_filter.rb +71 -0
- data/lib/bitcoin/chain_params.rb +8 -0
- data/lib/bitcoin/constants.rb +8 -1
- data/lib/bitcoin/ext_key.rb +0 -4
- data/lib/bitcoin/key.rb +31 -7
- data/lib/bitcoin/message/block_transaction_request.rb +45 -0
- data/lib/bitcoin/message/block_transactions.rb +31 -0
- data/lib/bitcoin/message/block_txn.rb +27 -0
- data/lib/bitcoin/message/cmpct_block.rb +42 -0
- data/lib/bitcoin/message/get_block_txn.rb +27 -0
- data/lib/bitcoin/message/header_and_short_ids.rb +57 -0
- data/lib/bitcoin/message/prefilled_tx.rb +29 -0
- data/lib/bitcoin/message/send_cmpct.rb +1 -1
- data/lib/bitcoin/message/version.rb +1 -1
- data/lib/bitcoin/message.rb +7 -0
- data/lib/bitcoin/network/message_handler.rb +7 -1
- data/lib/bitcoin/network/peer.rb +26 -4
- data/lib/bitcoin/network/pool.rb +17 -1
- data/lib/bitcoin/node/cli.rb +5 -0
- data/lib/bitcoin/node/configuration.rb +1 -0
- data/lib/bitcoin/node/spv.rb +21 -1
- data/lib/bitcoin/rpc/request_handler.rb +6 -0
- data/lib/bitcoin/script/script.rb +4 -1
- data/lib/bitcoin/script/script_interpreter.rb +5 -18
- data/lib/bitcoin/secp256k1/native.rb +9 -3
- data/lib/bitcoin/secp256k1/ruby.rb +51 -23
- data/lib/bitcoin/secp256k1.rb +2 -0
- data/lib/bitcoin/store/chain_entry.rb +1 -2
- data/lib/bitcoin/store/db/level_db.rb +2 -3
- data/lib/bitcoin/store/spv_chain.rb +1 -1
- data/lib/bitcoin/tx.rb +8 -4
- data/lib/bitcoin/tx_in.rb +3 -0
- data/lib/bitcoin/tx_out.rb +3 -0
- data/lib/bitcoin/util.rb +3 -0
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin/wallet/account.rb +3 -3
- data/lib/bitcoin/wallet/base.rb +15 -1
- data/lib/bitcoin/wallet/db.rb +9 -2
- data/lib/bitcoin.rb +23 -3
- metadata +25 -3
data/lib/bitcoin/network/pool.rb
CHANGED
@@ -26,6 +26,7 @@ module Bitcoin
|
|
26
26
|
@max_outbound = MAX_OUTBOUND_CONNECTIONS
|
27
27
|
@chain = chain
|
28
28
|
@logger = Bitcoin::Logger.create(:debug)
|
29
|
+
@configuration = configuration
|
29
30
|
@peer_discovery = PeerDiscovery.new(configuration)
|
30
31
|
@started = false
|
31
32
|
end
|
@@ -39,7 +40,7 @@ module Bitcoin
|
|
39
40
|
port = Bitcoin.chain_params.default_port
|
40
41
|
EM::Iterator.new(addr_list, Bitcoin::PARALLEL_THREAD).each do |ip, iter|
|
41
42
|
if pending_peers.size < MAX_OUTBOUND_CONNECTIONS
|
42
|
-
peer = Peer.new(ip, port, self)
|
43
|
+
peer = Peer.new(ip, port, self, @configuration)
|
43
44
|
pending_peers << peer
|
44
45
|
peer.connect
|
45
46
|
iter.next
|
@@ -73,6 +74,21 @@ module Bitcoin
|
|
73
74
|
peers.each { |peer| peer.broadcast_tx(tx) }
|
74
75
|
end
|
75
76
|
|
77
|
+
# new bloom filter.
|
78
|
+
def filter_load(bloom)
|
79
|
+
peers.each { |peer| peer.send_filter_load(bloom) }
|
80
|
+
end
|
81
|
+
|
82
|
+
# add element to bloom filter.
|
83
|
+
def filter_add(element)
|
84
|
+
peers.each { |peer| peer.send_filter_add(element) }
|
85
|
+
end
|
86
|
+
|
87
|
+
# clear bloom filter.
|
88
|
+
def filter_clear
|
89
|
+
peers.each { |peer| peer.send_filter_clear }
|
90
|
+
end
|
91
|
+
|
76
92
|
def handle_error(e)
|
77
93
|
terminate
|
78
94
|
end
|
data/lib/bitcoin/node/cli.rb
CHANGED
data/lib/bitcoin/node/spv.rb
CHANGED
@@ -10,6 +10,7 @@ module Bitcoin
|
|
10
10
|
attr_accessor :running
|
11
11
|
attr_reader :configuration
|
12
12
|
attr_accessor :server
|
13
|
+
attr_accessor :wallet
|
13
14
|
|
14
15
|
def initialize(configuration)
|
15
16
|
@chain = Bitcoin::Store::SPVChain.new
|
@@ -17,6 +18,10 @@ module Bitcoin
|
|
17
18
|
@pool = Bitcoin::Network::Pool.new(@chain, @configuration)
|
18
19
|
@logger = Bitcoin::Logger.create(:debug)
|
19
20
|
@running = false
|
21
|
+
@wallet = Bitcoin::Wallet::Base.current_wallet
|
22
|
+
# TODO : optimize bloom filter parameters
|
23
|
+
# TODO : load public keys in wallet.
|
24
|
+
@bloom = Bitcoin::BloomFilter.new(512, 0.01)
|
20
25
|
end
|
21
26
|
|
22
27
|
# open the node.
|
@@ -43,7 +48,22 @@ module Bitcoin
|
|
43
48
|
logger.debug "broadcast tx: #{tx.to_payload.bth}"
|
44
49
|
end
|
45
50
|
|
46
|
-
|
51
|
+
# new bloom filter.
|
52
|
+
def filter_load
|
53
|
+
pool.filter_load(@bloom)
|
54
|
+
end
|
55
|
+
|
56
|
+
# add filter element to bloom filter.
|
57
|
+
# [String] element. the hex string of txid, public key, public key hash or outpoint.
|
58
|
+
def filter_add(element)
|
59
|
+
@bloom.add(element)
|
60
|
+
pool.filter_add(element)
|
61
|
+
end
|
47
62
|
|
63
|
+
# clear bloom filter.
|
64
|
+
def filter_clear
|
65
|
+
pool.filter_clear
|
66
|
+
end
|
67
|
+
end
|
48
68
|
end
|
49
69
|
end
|
@@ -92,6 +92,12 @@ module Bitcoin
|
|
92
92
|
Bitcoin::Wallet::Base.wallet_paths(wallet_path_prefix)
|
93
93
|
end
|
94
94
|
|
95
|
+
# get current wallet information.
|
96
|
+
def getwalletinfo
|
97
|
+
return {} unless node.wallet
|
98
|
+
{wallet_id: node.wallet.wallet_id, version: node.wallet.version}
|
99
|
+
end
|
100
|
+
|
95
101
|
end
|
96
102
|
|
97
103
|
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# Porting part of the code from bitcoin-ruby. see the license.
|
2
|
+
# https://github.com/lian/bitcoin-ruby/blob/master/COPYING
|
3
|
+
|
1
4
|
module Bitcoin
|
2
5
|
|
3
6
|
# bitcoin script
|
@@ -304,7 +307,7 @@ module Bitcoin
|
|
304
307
|
return '' if i == 0
|
305
308
|
negative = i < 0
|
306
309
|
|
307
|
-
hex = i.abs.
|
310
|
+
hex = i.abs.to_even_length_hex
|
308
311
|
hex = '0' + hex unless (hex.length % 2).zero?
|
309
312
|
v = hex.htb.reverse # change endian
|
310
313
|
|
@@ -14,7 +14,7 @@ module Bitcoin
|
|
14
14
|
DISABLE_OPCODES = [OP_CAT, OP_SUBSTR, OP_LEFT, OP_RIGHT, OP_INVERT, OP_AND, OP_OR, OP_XOR, OP_2MUL, OP_2DIV, OP_DIV, OP_MUL, OP_MOD, OP_LSHIFT, OP_RSHIFT]
|
15
15
|
|
16
16
|
# initialize runner
|
17
|
-
def initialize(flags:
|
17
|
+
def initialize(flags: SCRIPT_VERIFY_NONE, checker: TxChecker.new)
|
18
18
|
@stack, @debug = [], []
|
19
19
|
@flags = flags
|
20
20
|
@checker = checker
|
@@ -219,10 +219,7 @@ module Bitcoin
|
|
219
219
|
when OP_NOP1, OP_NOP4..OP_NOP10
|
220
220
|
return set_error(SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS) if flag?(SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
221
221
|
when OP_CHECKLOCKTIMEVERIFY
|
222
|
-
unless flag?(SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
|
223
|
-
return set_error(SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS) if flag?(SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
224
|
-
next
|
225
|
-
end
|
222
|
+
next unless flag?(SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
|
226
223
|
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
227
224
|
# Note that elsewhere numeric opcodes are limited to operands in the range -2**31+1 to 2**31-1,
|
228
225
|
# however it is legal for opcodes to produce results exceeding that range.
|
@@ -235,12 +232,7 @@ module Bitcoin
|
|
235
232
|
return set_error(SCRIPT_ERR_NEGATIVE_LOCKTIME) if locktime < 0
|
236
233
|
return set_error(SCRIPT_ERR_UNSATISFIED_LOCKTIME) unless checker.check_locktime(locktime)
|
237
234
|
when OP_CHECKSEQUENCEVERIFY
|
238
|
-
unless flag?(SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
|
239
|
-
if flag?(SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
240
|
-
return set_error(SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS)
|
241
|
-
end
|
242
|
-
next
|
243
|
-
end
|
235
|
+
next unless flag?(SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
|
244
236
|
return set_error(SCRIPT_ERR_INVALID_STACK_OPERATION) if stack.size < 1
|
245
237
|
|
246
238
|
# nSequence, like nLockTime, is a 32-bit unsigned integer field.
|
@@ -522,13 +514,7 @@ module Bitcoin
|
|
522
514
|
private
|
523
515
|
|
524
516
|
def flag?(flag)
|
525
|
-
(
|
526
|
-
end
|
527
|
-
|
528
|
-
def all_flags
|
529
|
-
result = SCRIPT_VERIFY_NONE
|
530
|
-
flags.each{ |f| result |= f }
|
531
|
-
result
|
517
|
+
(flags & flag) != 0
|
532
518
|
end
|
533
519
|
|
534
520
|
# pop the item with the int value for the number specified by +count+ from the stack.
|
@@ -610,6 +596,7 @@ module Bitcoin
|
|
610
596
|
return false if sig.empty?
|
611
597
|
s = sig.unpack('C*')
|
612
598
|
hash_type = s[-1] & (~(SIGHASH_TYPE[:anyonecanpay]))
|
599
|
+
hash_type &= (~(Bitcoin::SIGHASH_FORK_ID)) if Bitcoin.chain_params.fork_chain? # for fork coin.
|
613
600
|
return false if hash_type < SIGHASH_TYPE[:all] || hash_type > SIGHASH_TYPE[:single]
|
614
601
|
true
|
615
602
|
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# Porting part of the code from bitcoin-ruby. see the license.
|
2
|
+
# https://github.com/lian/bitcoin-ruby/blob/master/COPYING
|
3
|
+
|
1
4
|
module Bitcoin
|
2
5
|
module Secp256k1
|
3
6
|
|
@@ -101,9 +104,13 @@ module Bitcoin
|
|
101
104
|
Bitcoin::Key.new(priv_key: privkey, pubkey: pubkey, compressed: compressed)
|
102
105
|
end
|
103
106
|
|
104
|
-
|
107
|
+
# sign data.
|
108
|
+
# @param [String] data a data to be signed with binary format
|
109
|
+
# @param [String] privkey a private key using sign
|
110
|
+
# @return [String] signature data with binary format
|
111
|
+
def sign_data(data, privkey)
|
105
112
|
with_context do |context|
|
106
|
-
secret = FFI::MemoryPointer.new(:uchar,
|
113
|
+
secret = FFI::MemoryPointer.new(:uchar, privkey.htb.bytesize).put_bytes(0, privkey.htb)
|
107
114
|
raise 'priv_key invalid' unless secp256k1_ec_seckey_verify(context, secret)
|
108
115
|
|
109
116
|
internal_signature = FFI::MemoryPointer.new(:uchar, 64)
|
@@ -137,7 +144,6 @@ module Bitcoin
|
|
137
144
|
signature = FFI::MemoryPointer.new(:uchar, sig.bytesize).put_bytes(0, sig)
|
138
145
|
internal_signature = FFI::MemoryPointer.new(:uchar, 64)
|
139
146
|
result = secp256k1_ecdsa_signature_parse_der(context, internal_signature, signature, signature.size)
|
140
|
-
#result = ecdsa_signature_parse_der_lax(context, internal_signature, signature, signature.size)
|
141
147
|
return false unless result
|
142
148
|
|
143
149
|
# libsecp256k1's ECDSA verification requires lower-S signatures, which have not historically been enforced in Bitcoin, so normalize them first.
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Bitcoin
|
2
2
|
module Secp256k1
|
3
3
|
|
4
|
-
GROUP = ECDSA::Group::Secp256k1
|
5
|
-
|
6
4
|
# secp256 module using ecdsa gem
|
7
5
|
# https://github.com/DavidEGrayson/ruby_ecdsa
|
8
6
|
module Ruby
|
@@ -25,19 +23,35 @@ module Bitcoin
|
|
25
23
|
end
|
26
24
|
|
27
25
|
# sign data.
|
28
|
-
# @param [String] data a data to be signed
|
26
|
+
# @param [String] data a data to be signed with binary format
|
29
27
|
# @param [String] privkey a private key using sign
|
30
28
|
# @return [String] signature data with binary format
|
31
29
|
def sign_data(data, privkey)
|
32
|
-
|
33
|
-
private_key = ECDSA::Format::IntegerOctetString.decode(privkey
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
30
|
+
privkey = privkey.htb
|
31
|
+
private_key = ECDSA::Format::IntegerOctetString.decode(privkey)
|
32
|
+
nonce = generate_rfc6979_nonce(data, privkey)
|
33
|
+
|
34
|
+
# port form ecdsa gem.
|
35
|
+
r_point = GROUP.new_point(nonce)
|
36
|
+
|
37
|
+
point_field = ECDSA::PrimeField.new(GROUP.order)
|
38
|
+
r = point_field.mod(r_point.x)
|
39
|
+
return nil if r.zero?
|
40
|
+
|
41
|
+
e = ECDSA.normalize_digest(data, GROUP.bit_length)
|
42
|
+
s = point_field.mod(point_field.inverse(nonce) * (e + r * private_key))
|
43
|
+
|
44
|
+
if s > (GROUP.order / 2) # convert low-s
|
45
|
+
s = GROUP.order - s
|
39
46
|
end
|
40
|
-
|
47
|
+
|
48
|
+
return nil if s.zero?
|
49
|
+
|
50
|
+
signature = ECDSA::Signature.new(r, s)
|
51
|
+
public_key = Bitcoin::Key.new(priv_key: privkey.bth).pubkey
|
52
|
+
signature = ECDSA::Format::SignatureDerString.encode(signature) # signature with DER format
|
53
|
+
raise 'Creation of signature failed.' unless Bitcoin::Secp256k1::Ruby.verify_sig(data, signature, public_key)
|
54
|
+
signature
|
41
55
|
end
|
42
56
|
|
43
57
|
# verify signature using public key
|
@@ -48,24 +62,13 @@ module Bitcoin
|
|
48
62
|
def verify_sig(digest, sig, pubkey)
|
49
63
|
begin
|
50
64
|
k = ECDSA::Format::PointOctetString.decode(repack_pubkey(pubkey), GROUP)
|
51
|
-
signature =
|
65
|
+
signature = ECDSA::Format::SignatureDerString.decode(sig)
|
52
66
|
ECDSA.valid_signature?(k, digest, signature)
|
53
67
|
rescue Exception
|
54
68
|
false
|
55
69
|
end
|
56
70
|
end
|
57
71
|
|
58
|
-
# repack signature for OpenSSL 1.0.1k handling of DER signatures
|
59
|
-
# https://github.com/bitcoin/bitcoin/pull/5634/files
|
60
|
-
def repack_sig(sig)
|
61
|
-
sig_array = sig.unpack('C*')
|
62
|
-
len_r = sig_array[3]
|
63
|
-
r = sig_array[4...(len_r+4)].pack('C*').bth
|
64
|
-
len_s = sig_array[len_r + 5]
|
65
|
-
s = sig_array[(len_r + 6)...(len_r + 6 + len_s)].pack('C*').bth
|
66
|
-
ECDSA::Signature.new(r.to_i(16), s.to_i(16))
|
67
|
-
end
|
68
|
-
|
69
72
|
# if +pubkey+ is hybrid public key format, it convert uncompressed format.
|
70
73
|
# https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2012-June/001578.html
|
71
74
|
def repack_pubkey(pubkey)
|
@@ -79,6 +82,31 @@ module Bitcoin
|
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
85
|
+
# generate temporary key k to be used when ECDSA sign.
|
86
|
+
# https://tools.ietf.org/html/rfc6979#section-3.2
|
87
|
+
def generate_rfc6979_nonce(data, privkey)
|
88
|
+
v = ('01' * 32).htb
|
89
|
+
k = ('00' * 32).htb
|
90
|
+
# 3.2.d
|
91
|
+
k = Bitcoin.hmac_sha256(k, v + '00'.htb + privkey + data)
|
92
|
+
# 3.2.e
|
93
|
+
v = Bitcoin.hmac_sha256(k, v)
|
94
|
+
# 3.2.f
|
95
|
+
k = Bitcoin.hmac_sha256(k, v + '01'.htb + privkey + data)
|
96
|
+
# 3.2.g
|
97
|
+
v = Bitcoin.hmac_sha256(k, v)
|
98
|
+
# 3.2.h
|
99
|
+
t = ''
|
100
|
+
10000.times do
|
101
|
+
v = Bitcoin.hmac_sha256(k, v)
|
102
|
+
t = (t + v)
|
103
|
+
t_num = t.bth.to_i(16)
|
104
|
+
return t_num if 1 <= t_num && t_num < GROUP.order
|
105
|
+
k = Bitcoin.hmac_sha256(k, v + '00'.htb)
|
106
|
+
v = Bitcoin.hmac_sha256(v)
|
107
|
+
end
|
108
|
+
raise 'A valid nonce was not found.'
|
109
|
+
end
|
82
110
|
end
|
83
111
|
|
84
112
|
end
|
data/lib/bitcoin/secp256k1.rb
CHANGED
@@ -51,8 +51,7 @@ module Bitcoin
|
|
51
51
|
|
52
52
|
# generate payload
|
53
53
|
def to_payload
|
54
|
-
height_value = height.
|
55
|
-
height_value = '0' + height_value if height_value.length.odd?
|
54
|
+
height_value = height.to_even_length_hex
|
56
55
|
height_value = height_value.htb.reverse
|
57
56
|
Bitcoin.pack_var_int(height_value.bytesize) + height_value + header.to_payload
|
58
57
|
end
|
@@ -74,8 +74,7 @@ module Bitcoin
|
|
74
74
|
|
75
75
|
# generate height key
|
76
76
|
def height_key(height)
|
77
|
-
height = height.
|
78
|
-
height = '0' + height if height.bytesize.odd?
|
77
|
+
height = height.to_even_length_hex
|
79
78
|
KEY_PREFIX[:height] + height.htb.reverse.bth
|
80
79
|
end
|
81
80
|
|
@@ -98,4 +97,4 @@ module Bitcoin
|
|
98
97
|
|
99
98
|
end
|
100
99
|
end
|
101
|
-
end
|
100
|
+
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.
|
46
|
+
logger.info("append header #{header.hash}")
|
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
@@ -1,3 +1,6 @@
|
|
1
|
+
# Porting part of the code from bitcoin-ruby. see the license.
|
2
|
+
# https://github.com/lian/bitcoin-ruby/blob/master/COPYING
|
3
|
+
|
1
4
|
module Bitcoin
|
2
5
|
|
3
6
|
# Transaction class
|
@@ -178,7 +181,7 @@ module Bitcoin
|
|
178
181
|
raise ArgumentError, 'script_pubkey must be specified.' unless output_script
|
179
182
|
raise ArgumentError, 'unsupported sig version specified.' unless SIG_VERSION.include?(sig_version)
|
180
183
|
|
181
|
-
if sig_version == :witness_v0
|
184
|
+
if sig_version == :witness_v0 || Bitcoin.chain_params.fork_chain?
|
182
185
|
raise ArgumentError, 'amount must be specified.' unless amount
|
183
186
|
sighash_for_witness(input_index, output_script, hash_type, amount, skip_separator_index)
|
184
187
|
else
|
@@ -201,7 +204,7 @@ module Bitcoin
|
|
201
204
|
script_pubkey = redeem_script if redeem_script.p2wpkh?
|
202
205
|
end
|
203
206
|
|
204
|
-
if has_witness
|
207
|
+
if has_witness || Bitcoin.chain_params.fork_chain?
|
205
208
|
verify_input_sig_for_witness(input_index, script_pubkey, amount, flags)
|
206
209
|
else
|
207
210
|
verify_input_sig_for_legacy(input_index, script_pubkey, flags)
|
@@ -271,6 +274,7 @@ module Bitcoin
|
|
271
274
|
if (hash_type & SIGHASH_TYPE[:anyonecanpay]) != 0
|
272
275
|
hash_prevouts = hash_sequence ="\x00".ljust(32, "\x00")
|
273
276
|
end
|
277
|
+
hash_type |= (Bitcoin.chain_params.fork_id << 8) if Bitcoin.chain_params.fork_chain?
|
274
278
|
buf = [ [version].pack('V'), hash_prevouts, hash_sequence, outpoint,
|
275
279
|
script_code ,amount, nsequence, hash_outputs, [@lock_time, hash_type].pack('VV')].join
|
276
280
|
Bitcoin.double_sha256(buf)
|
@@ -287,8 +291,8 @@ module Bitcoin
|
|
287
291
|
|
288
292
|
# verify input signature for witness tx.
|
289
293
|
def verify_input_sig_for_witness(input_index, script_pubkey, amount, flags)
|
290
|
-
flags
|
291
|
-
flags
|
294
|
+
flags |= SCRIPT_VERIFY_WITNESS
|
295
|
+
flags |= SCRIPT_VERIFY_WITNESS_PUBKEYTYPE
|
292
296
|
checker = Bitcoin::TxChecker.new(tx: self, input_index: input_index, amount: amount)
|
293
297
|
interpreter = Bitcoin::ScriptInterpreter.new(checker: checker, flags: flags)
|
294
298
|
i = inputs[input_index]
|
data/lib/bitcoin/tx_in.rb
CHANGED
data/lib/bitcoin/tx_out.rb
CHANGED
data/lib/bitcoin/util.rb
CHANGED
data/lib/bitcoin/version.rb
CHANGED
@@ -54,12 +54,12 @@ module Bitcoin
|
|
54
54
|
|
55
55
|
# derive receive key
|
56
56
|
def derive_receive(address_index)
|
57
|
-
|
57
|
+
derive_key(0, address_index)
|
58
58
|
end
|
59
59
|
|
60
60
|
# derive change key
|
61
61
|
def derive_change(address_index)
|
62
|
-
|
62
|
+
derive_key(1, address_index)
|
63
63
|
end
|
64
64
|
|
65
65
|
# save this account payload to database.
|
@@ -74,7 +74,7 @@ module Bitcoin
|
|
74
74
|
|
75
75
|
# get the list of derived keys for change key.
|
76
76
|
def derived_change_keys
|
77
|
-
|
77
|
+
change_depth.times.map{|i|derive_key(1,i)}
|
78
78
|
end
|
79
79
|
|
80
80
|
private
|
data/lib/bitcoin/wallet/base.rb
CHANGED
@@ -9,6 +9,7 @@ module Bitcoin
|
|
9
9
|
attr_reader :path
|
10
10
|
|
11
11
|
DEFAULT_PATH_PREFIX = "#{Bitcoin.base_dir}/db/wallet/"
|
12
|
+
VERSION = 1
|
12
13
|
|
13
14
|
# Create new wallet. If wallet already exist, throw error.
|
14
15
|
# The wallet generates a seed using SecureRandom and store to db at initialization.
|
@@ -36,7 +37,15 @@ module Bitcoin
|
|
36
37
|
# get wallets path
|
37
38
|
# @return [Array] Array of paths for each wallet dir.
|
38
39
|
def self.wallet_paths(path_prefix = DEFAULT_PATH_PREFIX)
|
39
|
-
Dir.glob("#{path_prefix}wallet*/")
|
40
|
+
Dir.glob("#{path_prefix}wallet*/").sort
|
41
|
+
end
|
42
|
+
|
43
|
+
# get current wallet
|
44
|
+
def self.current_wallet(path_prefix = DEFAULT_PATH_PREFIX)
|
45
|
+
path = wallet_paths.first # TODO default wallet selection
|
46
|
+
return nil unless path
|
47
|
+
wallet_id = path.delete(path_prefix + '/wallet').delete('/').to_i
|
48
|
+
self.load(wallet_id, path_prefix)
|
40
49
|
end
|
41
50
|
|
42
51
|
# get account list based on BIP-44
|
@@ -55,6 +64,11 @@ module Bitcoin
|
|
55
64
|
account
|
56
65
|
end
|
57
66
|
|
67
|
+
# get wallet version.
|
68
|
+
def version
|
69
|
+
db.version
|
70
|
+
end
|
71
|
+
|
58
72
|
# close database wallet
|
59
73
|
def close
|
60
74
|
db.close
|
data/lib/bitcoin/wallet/db.rb
CHANGED
@@ -5,7 +5,8 @@ module Bitcoin
|
|
5
5
|
|
6
6
|
KEY_PREFIX = {
|
7
7
|
account: 'a', # key: account index, value: Account raw data.
|
8
|
-
master: 'm',
|
8
|
+
master: 'm', # value: wallet seed.
|
9
|
+
version: 'v', # value: wallet version
|
9
10
|
}
|
10
11
|
|
11
12
|
attr_reader :level_db
|
@@ -44,6 +45,7 @@ module Bitcoin
|
|
44
45
|
# @param [Bitcoin::Wallet::MasterKey] master a master key.
|
45
46
|
def register_master_key(master)
|
46
47
|
level_db.put(KEY_PREFIX[:master], master.to_payload)
|
48
|
+
level_db.put(KEY_PREFIX[:version], Bitcoin::Wallet::Base::VERSION.to_s)
|
47
49
|
@master_key = master
|
48
50
|
end
|
49
51
|
|
@@ -52,6 +54,11 @@ module Bitcoin
|
|
52
54
|
!level_db.get(KEY_PREFIX[:master]).nil?
|
53
55
|
end
|
54
56
|
|
57
|
+
# wallet version
|
58
|
+
def version
|
59
|
+
level_db.get(KEY_PREFIX[:version]).to_i
|
60
|
+
end
|
61
|
+
|
55
62
|
end
|
56
63
|
end
|
57
|
-
end
|
64
|
+
end
|
data/lib/bitcoin.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# Porting part of the code from bitcoin-ruby. see the license.
|
2
|
+
# https://github.com/lian/bitcoin-ruby/blob/master/COPYING
|
3
|
+
|
1
4
|
require 'bitcoin/version'
|
2
5
|
require 'eventmachine'
|
3
6
|
require 'ecdsa'
|
@@ -39,6 +42,7 @@ module Bitcoin
|
|
39
42
|
autoload :Store, 'bitcoin/store'
|
40
43
|
autoload :RPC, 'bitcoin/rpc'
|
41
44
|
autoload :Wallet, 'bitcoin/wallet'
|
45
|
+
autoload :BloomFilter, 'bitcoin/bloom_filter'
|
42
46
|
|
43
47
|
require_relative 'bitcoin/constants'
|
44
48
|
|
@@ -58,12 +62,13 @@ module Bitcoin
|
|
58
62
|
return @current_chain if @current_chain
|
59
63
|
case @chain_param
|
60
64
|
when :mainnet
|
61
|
-
Bitcoin::ChainParams.mainnet
|
65
|
+
@current_chain = Bitcoin::ChainParams.mainnet
|
62
66
|
when :testnet
|
63
|
-
Bitcoin::ChainParams.testnet
|
67
|
+
@current_chain = Bitcoin::ChainParams.testnet
|
64
68
|
when :regtest
|
65
|
-
Bitcoin::ChainParams.regtest
|
69
|
+
@current_chain = Bitcoin::ChainParams.regtest
|
66
70
|
end
|
71
|
+
@current_chain
|
67
72
|
end
|
68
73
|
|
69
74
|
# base dir path that store blockchain data and wallet data
|
@@ -77,6 +82,14 @@ module Bitcoin
|
|
77
82
|
(path && File.exist?(path)) ? Bitcoin::Secp256k1::Native : Bitcoin::Secp256k1::Ruby
|
78
83
|
end
|
79
84
|
|
85
|
+
def self.hmac_sha512(key, data)
|
86
|
+
OpenSSL::HMAC.digest(OpenSSL::Digest.new('SHA512'), key, data)
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.hmac_sha256(key, data)
|
90
|
+
OpenSSL::HMAC.digest(OpenSSL::Digest.new('SHA256'), key, data)
|
91
|
+
end
|
92
|
+
|
80
93
|
class ::String
|
81
94
|
# binary convert to hex string
|
82
95
|
def bth
|
@@ -140,6 +153,7 @@ module Bitcoin
|
|
140
153
|
end
|
141
154
|
|
142
155
|
def to_h
|
156
|
+
return self if self.is_a?(String)
|
143
157
|
instance_variables.inject({}) do |result, var|
|
144
158
|
key = var.to_s
|
145
159
|
key.slice!(0) if key.start_with?('@')
|
@@ -154,4 +168,10 @@ module Bitcoin
|
|
154
168
|
|
155
169
|
end
|
156
170
|
|
171
|
+
class ::Integer
|
172
|
+
def to_even_length_hex
|
173
|
+
hex = to_s(16)
|
174
|
+
hex.rjust((hex.length / 2.0).ceil * 2, '0')
|
175
|
+
end
|
176
|
+
end
|
157
177
|
end
|