bitcoin-ruby 0.0.10 → 0.0.11
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/.travis.yml +1 -0
- data/COPYING +1 -1
- data/Gemfile.lock +9 -10
- data/README.rdoc +1 -1
- data/Rakefile +4 -2
- data/lib/bitcoin.rb +4 -2
- data/lib/bitcoin/bloom_filter.rb +125 -0
- data/lib/bitcoin/builder.rb +34 -9
- data/lib/bitcoin/ext_key.rb +191 -0
- data/lib/bitcoin/ffi/openssl.rb +1 -1
- data/lib/bitcoin/key.rb +6 -4
- data/lib/bitcoin/protocol.rb +13 -11
- data/lib/bitcoin/protocol/block.rb +38 -2
- data/lib/bitcoin/protocol/parser.rb +8 -0
- data/lib/bitcoin/protocol/partial_merkle_tree.rb +61 -0
- data/lib/bitcoin/protocol/script_witness.rb +31 -0
- data/lib/bitcoin/protocol/tx.rb +170 -10
- data/lib/bitcoin/protocol/txin.rb +8 -0
- data/lib/bitcoin/protocol/version.rb +2 -1
- data/lib/bitcoin/script.rb +58 -8
- data/lib/bitcoin/version.rb +1 -1
- data/spec/bitcoin/bloom_filter_spec.rb +23 -0
- data/spec/bitcoin/builder_spec.rb +12 -0
- data/spec/bitcoin/ext_key_spec.rb +180 -0
- data/spec/bitcoin/fixtures/filteredblock-0.bin +0 -0
- data/spec/bitcoin/fixtures/rawblock-testnet-1151351.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-p2wpkh.bin +0 -0
- data/spec/bitcoin/fixtures/rawtx-p2wpkh.json +67 -0
- data/spec/bitcoin/fixtures/tx-0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3.json +139 -0
- data/spec/bitcoin/fixtures/tx-28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f.json +34 -0
- data/spec/bitcoin/protocol/bip143_spec.rb +116 -0
- data/spec/bitcoin/protocol/block_spec.rb +27 -0
- data/spec/bitcoin/protocol/partial_merkle_tree_spec.rb +38 -0
- data/spec/bitcoin/protocol/tx_spec.rb +134 -1
- data/spec/bitcoin/script/script_spec.rb +53 -2
- metadata +27 -3
@@ -20,6 +20,9 @@ module Bitcoin
|
|
20
20
|
# (used when dealing with unsigned or partly signed tx)
|
21
21
|
attr_accessor :sig_hash, :sig_address
|
22
22
|
|
23
|
+
# segregated witness
|
24
|
+
attr_accessor :script_witness
|
25
|
+
|
23
26
|
alias :script :script_sig
|
24
27
|
alias :script_length :script_sig_length
|
25
28
|
|
@@ -36,6 +39,7 @@ module Bitcoin
|
|
36
39
|
@script_sig_length ||= 0
|
37
40
|
@script_sig ||= ''
|
38
41
|
@sequence ||= DEFAULT_SEQUENCE
|
42
|
+
@script_witness = ScriptWitness.new
|
39
43
|
end
|
40
44
|
|
41
45
|
# compare to another txout
|
@@ -87,6 +91,7 @@ module Bitcoin
|
|
87
91
|
t['scriptSig'] = Bitcoin::Script.new(@script_sig).to_string
|
88
92
|
end
|
89
93
|
t['sequence'] = @sequence.unpack("V")[0] unless @sequence == "\xff\xff\xff\xff"
|
94
|
+
t['witness'] = @script_witness.stack.map{|s|s.bth} unless @script_witness.empty?
|
90
95
|
t
|
91
96
|
end
|
92
97
|
|
@@ -99,6 +104,9 @@ module Bitcoin
|
|
99
104
|
else
|
100
105
|
txin.script_sig = Script.binary_from_string(input['scriptSig'] || input['script'])
|
101
106
|
end
|
107
|
+
if input['witness']
|
108
|
+
input['witness'].each {|w| txin.script_witness.stack << w.htb}
|
109
|
+
end
|
102
110
|
txin.sequence = [ input['sequence'] || 0xffffffff ].pack("V")
|
103
111
|
txin
|
104
112
|
end
|
@@ -6,6 +6,7 @@ module Bitcoin
|
|
6
6
|
# https://en.bitcoin.it/wiki/Protocol_specification#version
|
7
7
|
class Version
|
8
8
|
# services bit constants
|
9
|
+
NODE_NONE = 0
|
9
10
|
NODE_NETWORK = (1 << 0)
|
10
11
|
|
11
12
|
attr_reader :fields
|
@@ -25,7 +26,7 @@ module Bitcoin
|
|
25
26
|
end
|
26
27
|
|
27
28
|
def to_payload
|
28
|
-
|
29
|
+
[
|
29
30
|
@fields.values_at(:version, :services, :time).pack("VQQ"),
|
30
31
|
pack_address_field(@fields[:from]),
|
31
32
|
pack_address_field(@fields[:to]),
|
data/lib/bitcoin/script.rb
CHANGED
@@ -297,6 +297,17 @@ class Bitcoin::Script
|
|
297
297
|
to_binary(buf)
|
298
298
|
end
|
299
299
|
|
300
|
+
# Returns a script that deleted the script before the index specified by separator_index.
|
301
|
+
def subscript_codeseparator(separator_index)
|
302
|
+
buf = []
|
303
|
+
process_separator_index = 0
|
304
|
+
(chunks || @chunks).each{|chunk|
|
305
|
+
buf << chunk if process_separator_index == separator_index
|
306
|
+
process_separator_index += 1 if chunk == OP_CODESEPARATOR and process_separator_index < separator_index
|
307
|
+
}
|
308
|
+
to_binary(buf)
|
309
|
+
end
|
310
|
+
|
300
311
|
# Adds opcode (OP_0, OP_1, ... OP_CHECKSIG etc.)
|
301
312
|
# Returns self.
|
302
313
|
def append_opcode(opcode)
|
@@ -540,7 +551,7 @@ class Bitcoin::Script
|
|
540
551
|
|
541
552
|
# check if script is in one of the recognized standard formats
|
542
553
|
def is_standard?
|
543
|
-
is_pubkey? || is_hash160? || is_multisig? || is_p2sh? || is_op_return?
|
554
|
+
is_pubkey? || is_hash160? || is_multisig? || is_p2sh? || is_op_return? || is_witness_v0_keyhash? || is_witness_v0_scripthash?
|
544
555
|
end
|
545
556
|
|
546
557
|
# is this a pubkey script
|
@@ -569,6 +580,21 @@ class Bitcoin::Script
|
|
569
580
|
@chunks[0] == OP_RETURN && @chunks.size <= 2
|
570
581
|
end
|
571
582
|
|
583
|
+
# is this a witness script(witness_v0_keyhash or witness_v0_scripthash)
|
584
|
+
def is_witness?
|
585
|
+
is_witness_v0_keyhash? || is_witness_v0_scripthash?
|
586
|
+
end
|
587
|
+
|
588
|
+
# is this a witness pubkey script
|
589
|
+
def is_witness_v0_keyhash?
|
590
|
+
@chunks.length == 2 &&@chunks[0] == 0 && @chunks[1].is_a?(String) && @chunks[1].bytesize == 20
|
591
|
+
end
|
592
|
+
|
593
|
+
# is this a witness script hash
|
594
|
+
def is_witness_v0_scripthash?
|
595
|
+
@chunks.length == 2 &&@chunks[0] == 0 && @chunks[1].is_a?(String) && @chunks[1].bytesize == 32
|
596
|
+
end
|
597
|
+
|
572
598
|
# Verify the script is only pushing data onto the stack
|
573
599
|
def is_push_only?(script_data=nil)
|
574
600
|
check_pushes(push_only=true, canonical_only=false, (script_data||@input_script))
|
@@ -612,19 +638,21 @@ class Bitcoin::Script
|
|
612
638
|
end
|
613
639
|
end
|
614
640
|
true
|
615
|
-
rescue
|
641
|
+
rescue
|
616
642
|
# catch parsing errors
|
617
643
|
false
|
618
644
|
end
|
619
645
|
|
620
646
|
# get type of this tx
|
621
647
|
def type
|
622
|
-
if is_hash160?;
|
623
|
-
elsif is_pubkey?;
|
624
|
-
elsif is_multisig?;
|
625
|
-
elsif is_p2sh?;
|
626
|
-
elsif is_op_return
|
627
|
-
|
648
|
+
if is_hash160?; :hash160
|
649
|
+
elsif is_pubkey?; :pubkey
|
650
|
+
elsif is_multisig?; :multisig
|
651
|
+
elsif is_p2sh?; :p2sh
|
652
|
+
elsif is_op_return?; :op_return
|
653
|
+
elsif is_witness_v0_keyhash?; :witness_v0_keyhash
|
654
|
+
elsif is_witness_v0_scripthash?;:witness_v0_scripthash
|
655
|
+
else; :unknown
|
628
656
|
end
|
629
657
|
end
|
630
658
|
|
@@ -644,6 +672,8 @@ class Bitcoin::Script
|
|
644
672
|
return @chunks[2..-3][0].unpack("H*")[0] if is_hash160?
|
645
673
|
return @chunks[-2].unpack("H*")[0] if is_p2sh?
|
646
674
|
return Bitcoin.hash160(get_pubkey) if is_pubkey?
|
675
|
+
return @chunks[1].unpack("H*")[0] if is_witness_v0_keyhash?
|
676
|
+
return @chunks[1].unpack("H*")[0] if is_witness_v0_scripthash?
|
647
677
|
end
|
648
678
|
|
649
679
|
# get the hash160 address for this hash160 script
|
@@ -713,6 +743,22 @@ class Bitcoin::Script
|
|
713
743
|
[ ["a9", "14", p2sh, "87"].join ].pack("H*")
|
714
744
|
end
|
715
745
|
|
746
|
+
# generate p2wpkh tx for given +address+. returns a raw binary script of the form:
|
747
|
+
# 0 <hash160>
|
748
|
+
def self.to_witness_hash160_script(hash160)
|
749
|
+
return nil unless hash160
|
750
|
+
# witness ver length hash160
|
751
|
+
[ ["00", "14", hash160].join ].pack("H*")
|
752
|
+
end
|
753
|
+
|
754
|
+
# generate p2wsh output script for given +p2sh+ sha256. returns a raw binary script of the form:
|
755
|
+
# 0 <p2sh>
|
756
|
+
def self.to_witness_p2sh_script(p2sh)
|
757
|
+
return nil unless p2sh
|
758
|
+
# witness ver length sha256
|
759
|
+
[ [ "00", "20", p2sh].join].pack("H*")
|
760
|
+
end
|
761
|
+
|
716
762
|
# generate hash160 or p2sh output script, depending on the type of the given +address+.
|
717
763
|
# see #to_hash160_script and #to_p2sh_script.
|
718
764
|
def self.to_address_script(address)
|
@@ -832,6 +878,10 @@ class Bitcoin::Script
|
|
832
878
|
@chunks[-2] - 80
|
833
879
|
end
|
834
880
|
|
881
|
+
def codeseparator_count
|
882
|
+
@chunks.select{|c|c == Bitcoin::Script::OP_CODESEPARATOR}.length
|
883
|
+
end
|
884
|
+
|
835
885
|
# This matches CScript::GetSigOpCount(bool fAccurate)
|
836
886
|
# Note: this does not cover P2SH script which is to be unserialized
|
837
887
|
# and checked explicitly when validating blocks.
|
data/lib/bitcoin/version.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'spec_helper.rb'
|
2
|
+
|
3
|
+
#
|
4
|
+
# following test cases are borrowed from
|
5
|
+
# https://github.com/bitcoinj/bitcoinj/blob/master/core/src/test/java/org/bitcoinj/core/BloomFilterTest.java
|
6
|
+
#
|
7
|
+
describe 'Bloom Filter' do
|
8
|
+
before do
|
9
|
+
@filter = Bitcoin::BloomFilter.new(3, 0.01, 2147483649)
|
10
|
+
|
11
|
+
@filter.add_data('99108ad8ed9bb6274d3980bab5a85c048f0950c8'.htb)
|
12
|
+
@filter.add_data('b5a2c786d9ef4658287ced5914b37a1b4aa32eee'.htb)
|
13
|
+
@filter.add_data('b9300670b4c5366e95b2699e8b18bc75e5f729c5'.htb)
|
14
|
+
end
|
15
|
+
it "#contains?" do
|
16
|
+
@filter.contains?('99108ad8ed9bb6274d3980bab5a85c048f0950c8'.htb).should == true
|
17
|
+
@filter.contains?('19108ad8ed9bb6274d3980bab5a85c048f0950c8'.htb).should == false
|
18
|
+
@filter.contains?('b5a2c786d9ef4658287ced5914b37a1b4aa32eee'.htb).should == true
|
19
|
+
end
|
20
|
+
it "#filter" do
|
21
|
+
@filter.filter.bth.should == 'ce4299'
|
22
|
+
end
|
23
|
+
end
|
@@ -92,6 +92,18 @@ describe "Bitcoin::Builder" do
|
|
92
92
|
tx2.out[2].value.should == 0
|
93
93
|
end
|
94
94
|
|
95
|
+
it "should build transactions with p2wpkh signatures" do
|
96
|
+
key = Bitcoin::Key.new('619c335025c7f4012e556c2a58b2506e30b8511b53ade95ea316fd8c3286feb9')
|
97
|
+
script_pubkey = '00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1'.htb
|
98
|
+
tx = build_tx do |t|
|
99
|
+
t.input do |i|
|
100
|
+
i.prev_out '8ac60eb9575db5b2d987e29f301b5b819ea83a5c6579d282d189cc04b8e151ef', 1, script_pubkey, 600000000
|
101
|
+
i.signature_key key
|
102
|
+
end
|
103
|
+
end
|
104
|
+
tx.verify_witness_input_signature(0, script_pubkey, 600000000).should == true
|
105
|
+
end
|
106
|
+
|
95
107
|
it "should allow txin.prev_out as tx or hash" do
|
96
108
|
prev_tx = @block.tx[0]
|
97
109
|
tx1 = build_tx do |t|
|
@@ -0,0 +1,180 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
require_relative 'spec_helper'
|
4
|
+
|
5
|
+
# BIP-32 test
|
6
|
+
# https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#Test_Vectors
|
7
|
+
describe Bitcoin::ExtKey do
|
8
|
+
|
9
|
+
describe 'Test Vector 1' do
|
10
|
+
|
11
|
+
before do
|
12
|
+
Bitcoin.network = :bitcoin
|
13
|
+
@master_key = Bitcoin::ExtKey.generate_master('000102030405060708090a0b0c0d0e0f'.htb)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'Chain m' do
|
17
|
+
@master_key.depth.should == 0
|
18
|
+
@master_key.number.should == 0
|
19
|
+
@master_key.fingerprint.should == '3442193e'
|
20
|
+
@master_key.chain_code.bth.should == '873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508'
|
21
|
+
@master_key.priv.should == 'e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35'
|
22
|
+
@master_key.addr.should == '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma'
|
23
|
+
@master_key.pub.should == '0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2'
|
24
|
+
@master_key.to_base58.should == 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi'
|
25
|
+
@master_key.ext_pubkey.to_base58.should == 'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8'
|
26
|
+
@master_key.ext_pubkey.pub.should == '0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2'
|
27
|
+
@master_key.ext_pubkey.addr.should == '15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'Chain m/0H' do
|
31
|
+
key = @master_key.derive(2**31)
|
32
|
+
key.depth.should == 1
|
33
|
+
key.fingerprint.should == '5c1bd648'
|
34
|
+
key.chain_code.bth.should == '47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141'
|
35
|
+
key.priv_key.priv.should == 'edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea'
|
36
|
+
key.to_base58.should == 'xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7'
|
37
|
+
key.ext_pubkey.to_base58.should == 'xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'Chain m/0H/1' do
|
41
|
+
key = @master_key.derive(2**31).derive(1)
|
42
|
+
key.depth.should == 2
|
43
|
+
key.fingerprint.should == 'bef5a2f9'
|
44
|
+
key.chain_code.bth.should == '2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19'
|
45
|
+
key.priv_key.priv.should == '3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368'
|
46
|
+
key.to_base58.should == 'xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs'
|
47
|
+
key.ext_pubkey.to_base58.should == 'xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ'
|
48
|
+
|
49
|
+
# pubkey derivation
|
50
|
+
ext_pubkey = @master_key.derive(2**31).ext_pubkey.derive(1)
|
51
|
+
ext_pubkey.to_base58.should == 'xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ'
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'Chain m/0H/1/2H' do
|
55
|
+
key = @master_key.derive(2**31).derive(1).derive(2**31 + 2)
|
56
|
+
key.depth.should == 3
|
57
|
+
key.fingerprint.should == 'ee7ab90c'
|
58
|
+
key.chain_code.bth.should == '04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f'
|
59
|
+
key.priv_key.priv.should == 'cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca'
|
60
|
+
key.to_base58.should == 'xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM'
|
61
|
+
key.ext_pubkey.to_base58.should == 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5'
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'Chain m/0H/1/2H/2' do
|
65
|
+
key = @master_key.derive(2**31).derive(1).derive(2**31 + 2).derive(2)
|
66
|
+
key.depth.should == 4
|
67
|
+
key.fingerprint.should == 'd880d7d8'
|
68
|
+
key.chain_code.bth.should == 'cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd'
|
69
|
+
key.priv_key.priv.should == '0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4'
|
70
|
+
key.to_base58.should == 'xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334'
|
71
|
+
key.ext_pubkey.to_base58.should == 'xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV'
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'Chain m/0H/1/2H/2/1000000000' do
|
75
|
+
key = @master_key.derive(2**31).derive(1).derive(2**31 + 2).derive(2).derive(1000000000)
|
76
|
+
key.depth.should == 5
|
77
|
+
key.fingerprint.should == 'd69aa102'
|
78
|
+
key.chain_code.bth.should == 'c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e'
|
79
|
+
key.priv_key.priv.should == '471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8'
|
80
|
+
key.to_base58.should == 'xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76'
|
81
|
+
key.ext_pubkey.to_base58.should == 'xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'Test Vector 2' do
|
86
|
+
before do
|
87
|
+
Bitcoin.network = :bitcoin
|
88
|
+
@master_key = Bitcoin::ExtKey.generate_master('fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542'.htb)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'Chain m' do
|
92
|
+
@master_key.depth.should == 0
|
93
|
+
@master_key.number.should == 0
|
94
|
+
@master_key.to_base58.should == 'xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U'
|
95
|
+
@master_key.ext_pubkey.to_base58.should == 'xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB'
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'Chain m/0' do
|
99
|
+
key = @master_key.derive(0)
|
100
|
+
key.depth.should == 1
|
101
|
+
key.number.should == 0
|
102
|
+
key.to_base58.should == 'xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt'
|
103
|
+
key.ext_pubkey.to_base58.should == 'xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH'
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'Chain m/0/2147483647H' do
|
107
|
+
key = @master_key.derive(0).derive(2**31 + 2147483647)
|
108
|
+
key.depth.should == 2
|
109
|
+
key.number.should == 2**31 + 2147483647
|
110
|
+
key.to_base58.should == 'xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9'
|
111
|
+
key.ext_pubkey.to_base58.should == 'xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a'
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'Chain m/0/2147483647H/1' do
|
115
|
+
key = @master_key.derive(0).derive(2**31 + 2147483647).derive(1)
|
116
|
+
key.depth.should == 3
|
117
|
+
key.number.should == 1
|
118
|
+
key.to_base58.should == 'xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef'
|
119
|
+
key.ext_pubkey.to_base58.should == 'xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon'
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'Chain m/0/2147483647H/1/2147483646H' do
|
123
|
+
key = @master_key.derive(0).derive(2**31 + 2147483647).derive(1).derive(2**31 + 2147483646)
|
124
|
+
key.depth.should == 4
|
125
|
+
key.number.should == 2**31 + 2147483646
|
126
|
+
key.to_base58.should == 'xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc'
|
127
|
+
key.ext_pubkey.to_base58.should == 'xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL'
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'Chain m/0/2147483647H/1/2147483646H/2' do
|
131
|
+
key = @master_key.derive(0).derive(2**31 + 2147483647).derive(1).derive(2**31 + 2147483646).derive(2)
|
132
|
+
key.depth.should == 5
|
133
|
+
key.number.should == 2
|
134
|
+
key.to_base58.should == 'xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j'
|
135
|
+
key.ext_pubkey.to_base58.should == 'xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt'
|
136
|
+
ext_pubkey = @master_key.derive(0).derive(2**31 + 2147483647).derive(1).derive(2**31 + 2147483646).ext_pubkey.derive(2)
|
137
|
+
ext_pubkey.to_base58.should == 'xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt'
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
describe 'import from base58 address' do
|
143
|
+
|
144
|
+
it 'import private key' do
|
145
|
+
# normal key
|
146
|
+
key = Bitcoin::ExtKey.from_base58('xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs')
|
147
|
+
key.depth.should == 2
|
148
|
+
key.number.should == 1
|
149
|
+
key.chain_code.bth.should == '2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19'
|
150
|
+
key.priv_key.priv.should == '3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368'
|
151
|
+
key.ext_pubkey.to_base58.should == 'xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ'
|
152
|
+
|
153
|
+
# hardended key
|
154
|
+
key = Bitcoin::ExtKey.from_base58('xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM')
|
155
|
+
key.depth.should == 3
|
156
|
+
key.number.should == 2**31 + 2
|
157
|
+
key.fingerprint.should == 'ee7ab90c'
|
158
|
+
key.chain_code.bth.should == '04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f'
|
159
|
+
key.priv_key.priv.should == 'cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca'
|
160
|
+
key.to_base58.should == 'xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM'
|
161
|
+
key.ext_pubkey.to_base58.should == 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5'
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'import public key' do
|
165
|
+
# normal key
|
166
|
+
key = Bitcoin::ExtPubkey.from_base58('xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ')
|
167
|
+
key.depth.should == 2
|
168
|
+
key.number.should == 1
|
169
|
+
key.chain_code.bth.should == '2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19'
|
170
|
+
key.to_base58.should == 'xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ'
|
171
|
+
|
172
|
+
# hardended key
|
173
|
+
key = Bitcoin::ExtPubkey.from_base58('xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5')
|
174
|
+
key.depth.should == 3
|
175
|
+
key.number.should == 2**31 + 2
|
176
|
+
key.fingerprint.should == 'ee7ab90c'
|
177
|
+
key.chain_code.bth.should == '04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f'
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,67 @@
|
|
1
|
+
{
|
2
|
+
"hash":"f22f5168cf0bc55a31003b0fc532152da551e1ec4289c4fd92e7ec512c6e87a0",
|
3
|
+
"ver":2,
|
4
|
+
"vin_sz":1,
|
5
|
+
"vout_sz":11,
|
6
|
+
"lock_time":0,
|
7
|
+
"size":501,
|
8
|
+
"in":[
|
9
|
+
{
|
10
|
+
"prev_out":{
|
11
|
+
"hash":"afa574cd5b2f6fa2de58d98289396f1f9cdc7f8bf866ce11523cb235c44588bd",
|
12
|
+
"n":6
|
13
|
+
},
|
14
|
+
"scriptSig":"",
|
15
|
+
"witness":[
|
16
|
+
"3044022042663b93c21eaef25e085104972bf23353fcc6d6d7b16cfd763dd42b67c0647c0220043b41da107479f121338a7168b0dcc6a1c5342824c7f21b4e158b4a4342ba8b01",
|
17
|
+
"0276a5322440576e15d4291bb86a966124b9ceaa636e77dd0e8de846e5b7ab4f8c"
|
18
|
+
]
|
19
|
+
}
|
20
|
+
],
|
21
|
+
"out":[
|
22
|
+
{
|
23
|
+
"value":"0.00100000",
|
24
|
+
"scriptPubKey":"0 d702116d39b3e09e9e470ffbdacb8b37585ae0cd"
|
25
|
+
},
|
26
|
+
{
|
27
|
+
"value":"0.00100000",
|
28
|
+
"scriptPubKey":"0 d493052ed9b65cc64b48929c6c7d9cf3511d305e"
|
29
|
+
},
|
30
|
+
{
|
31
|
+
"value":"0.00100000",
|
32
|
+
"scriptPubKey":"0 ba6d07e9673f1de012e485272b56eac8fd946b14"
|
33
|
+
},
|
34
|
+
{
|
35
|
+
"value":"0.00100000",
|
36
|
+
"scriptPubKey":"0 d03c27e774f0e5001111e8f15057373a5955d9af"
|
37
|
+
},
|
38
|
+
{
|
39
|
+
"value":"0.00100000",
|
40
|
+
"scriptPubKey":"0 92ee96db74d42c782e76934eb6bb540304d3a1cc"
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"value":"0.00100000",
|
44
|
+
"scriptPubKey":"0 3b4be4abc0ccaa1aaba16798c73cdcff9b8693f8"
|
45
|
+
},
|
46
|
+
{
|
47
|
+
"value":"0.00100000",
|
48
|
+
"scriptPubKey":"0 90b3985459e7dd82f61291664b9c0240c7a8862c"
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"value":"0.00100000",
|
52
|
+
"scriptPubKey":"0 4f7d64ee9de267e6dcf1da9a486c7a59e12a89ab"
|
53
|
+
},
|
54
|
+
{
|
55
|
+
"value":"0.00100000",
|
56
|
+
"scriptPubKey":"0 fbaa036f8fceda60dcef1cdf0c35445030e2730f"
|
57
|
+
},
|
58
|
+
{
|
59
|
+
"value":"46.35368340",
|
60
|
+
"scriptPubKey":"0 95e62aaa26435362b271eebc9ce3cb82b286ecc9"
|
61
|
+
},
|
62
|
+
{
|
63
|
+
"value":"0.00100000",
|
64
|
+
"scriptPubKey":"0 bbd4cf49fa3131169159289e2e3b6e851d23f9d4"
|
65
|
+
}
|
66
|
+
]
|
67
|
+
}
|