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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/COPYING +1 -1
  4. data/Gemfile.lock +9 -10
  5. data/README.rdoc +1 -1
  6. data/Rakefile +4 -2
  7. data/lib/bitcoin.rb +4 -2
  8. data/lib/bitcoin/bloom_filter.rb +125 -0
  9. data/lib/bitcoin/builder.rb +34 -9
  10. data/lib/bitcoin/ext_key.rb +191 -0
  11. data/lib/bitcoin/ffi/openssl.rb +1 -1
  12. data/lib/bitcoin/key.rb +6 -4
  13. data/lib/bitcoin/protocol.rb +13 -11
  14. data/lib/bitcoin/protocol/block.rb +38 -2
  15. data/lib/bitcoin/protocol/parser.rb +8 -0
  16. data/lib/bitcoin/protocol/partial_merkle_tree.rb +61 -0
  17. data/lib/bitcoin/protocol/script_witness.rb +31 -0
  18. data/lib/bitcoin/protocol/tx.rb +170 -10
  19. data/lib/bitcoin/protocol/txin.rb +8 -0
  20. data/lib/bitcoin/protocol/version.rb +2 -1
  21. data/lib/bitcoin/script.rb +58 -8
  22. data/lib/bitcoin/version.rb +1 -1
  23. data/spec/bitcoin/bloom_filter_spec.rb +23 -0
  24. data/spec/bitcoin/builder_spec.rb +12 -0
  25. data/spec/bitcoin/ext_key_spec.rb +180 -0
  26. data/spec/bitcoin/fixtures/filteredblock-0.bin +0 -0
  27. data/spec/bitcoin/fixtures/rawblock-testnet-1151351.bin +0 -0
  28. data/spec/bitcoin/fixtures/rawtx-p2wpkh.bin +0 -0
  29. data/spec/bitcoin/fixtures/rawtx-p2wpkh.json +67 -0
  30. data/spec/bitcoin/fixtures/tx-0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3.json +139 -0
  31. data/spec/bitcoin/fixtures/tx-28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f.json +34 -0
  32. data/spec/bitcoin/protocol/bip143_spec.rb +116 -0
  33. data/spec/bitcoin/protocol/block_spec.rb +27 -0
  34. data/spec/bitcoin/protocol/partial_merkle_tree_spec.rb +38 -0
  35. data/spec/bitcoin/protocol/tx_spec.rb +134 -1
  36. data/spec/bitcoin/script/script_spec.rb +53 -2
  37. 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
- payload = [
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]),
@@ -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 => ex
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?; :hash160
623
- elsif is_pubkey?; :pubkey
624
- elsif is_multisig?; :multisig
625
- elsif is_p2sh?; :p2sh
626
- elsif is_op_return?;:op_return
627
- else; :unknown
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.
@@ -1,3 +1,3 @@
1
1
  module Bitcoin
2
- VERSION = "0.0.10"
2
+ VERSION = "0.0.11"
3
3
  end
@@ -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
@@ -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
+ }