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