btcruby 0.0.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +18 -0
- data/.travis.yml +7 -0
- data/FAQ.md +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +18 -0
- data/HOWTO.md +17 -0
- data/LICENSE +19 -0
- data/README.md +59 -0
- data/Rakefile +6 -0
- data/TODO.txt +40 -0
- data/bin/console +19 -0
- data/btcruby.gemspec +20 -0
- data/documentation/address.md +73 -0
- data/documentation/base58.md +52 -0
- data/documentation/block.md +127 -0
- data/documentation/block_header.md +120 -0
- data/documentation/constants.md +88 -0
- data/documentation/data.md +54 -0
- data/documentation/diagnostics.md +90 -0
- data/documentation/extensions.md +76 -0
- data/documentation/hash_functions.md +58 -0
- data/documentation/hash_id.md +22 -0
- data/documentation/index.md +230 -0
- data/documentation/key.md +177 -0
- data/documentation/keychain.md +180 -0
- data/documentation/network.md +75 -0
- data/documentation/opcode.md +220 -0
- data/documentation/openssl.md +7 -0
- data/documentation/p2pkh.md +71 -0
- data/documentation/p2sh.md +64 -0
- data/documentation/proof_of_work.md +84 -0
- data/documentation/script.md +280 -0
- data/documentation/signature.md +71 -0
- data/documentation/transaction.md +213 -0
- data/documentation/transaction_builder.md +188 -0
- data/documentation/transaction_input.md +133 -0
- data/documentation/transaction_output.md +130 -0
- data/documentation/wif.md +72 -0
- data/documentation/wire_format.md +70 -0
- data/lib/btcruby/address.rb +296 -0
- data/lib/btcruby/base58.rb +108 -0
- data/lib/btcruby/big_number.rb +47 -0
- data/lib/btcruby/block.rb +170 -0
- data/lib/btcruby/block_header.rb +231 -0
- data/lib/btcruby/constants.rb +59 -0
- data/lib/btcruby/currency_formatter.rb +64 -0
- data/lib/btcruby/data.rb +98 -0
- data/lib/btcruby/diagnostics.rb +92 -0
- data/lib/btcruby/errors.rb +8 -0
- data/lib/btcruby/extensions.rb +65 -0
- data/lib/btcruby/hash_functions.rb +54 -0
- data/lib/btcruby/hash_id.rb +18 -0
- data/lib/btcruby/key.rb +517 -0
- data/lib/btcruby/keychain.rb +464 -0
- data/lib/btcruby/network.rb +73 -0
- data/lib/btcruby/opcode.rb +197 -0
- data/lib/btcruby/open_assets/asset.rb +35 -0
- data/lib/btcruby/open_assets/asset_address.rb +49 -0
- data/lib/btcruby/open_assets/asset_definition.rb +75 -0
- data/lib/btcruby/open_assets/asset_id.rb +24 -0
- data/lib/btcruby/open_assets/asset_marker.rb +94 -0
- data/lib/btcruby/open_assets/asset_processor.rb +377 -0
- data/lib/btcruby/open_assets/asset_transaction.rb +184 -0
- data/lib/btcruby/open_assets/asset_transaction_builder/errors.rb +15 -0
- data/lib/btcruby/open_assets/asset_transaction_builder/provider.rb +32 -0
- data/lib/btcruby/open_assets/asset_transaction_builder/result.rb +47 -0
- data/lib/btcruby/open_assets/asset_transaction_builder.rb +418 -0
- data/lib/btcruby/open_assets/asset_transaction_input.rb +64 -0
- data/lib/btcruby/open_assets/asset_transaction_output.rb +140 -0
- data/lib/btcruby/open_assets.rb +26 -0
- data/lib/btcruby/openssl.rb +536 -0
- data/lib/btcruby/proof_of_work.rb +110 -0
- data/lib/btcruby/safety.rb +26 -0
- data/lib/btcruby/script.rb +733 -0
- data/lib/btcruby/signature_hashtype.rb +37 -0
- data/lib/btcruby/transaction.rb +511 -0
- data/lib/btcruby/transaction_builder/errors.rb +15 -0
- data/lib/btcruby/transaction_builder/provider.rb +54 -0
- data/lib/btcruby/transaction_builder/result.rb +73 -0
- data/lib/btcruby/transaction_builder/signer.rb +28 -0
- data/lib/btcruby/transaction_builder.rb +520 -0
- data/lib/btcruby/transaction_input.rb +298 -0
- data/lib/btcruby/transaction_outpoint.rb +30 -0
- data/lib/btcruby/transaction_output.rb +315 -0
- data/lib/btcruby/version.rb +3 -0
- data/lib/btcruby/wif.rb +118 -0
- data/lib/btcruby/wire_format.rb +362 -0
- data/lib/btcruby.rb +44 -2
- data/sample_code/creating_a_p2sh_multisig_address.rb +21 -0
- data/sample_code/creating_a_transaction_manually.rb +44 -0
- data/sample_code/generating_an_address.rb +20 -0
- data/sample_code/using_transaction_builder.rb +49 -0
- data/spec/address_spec.rb +206 -0
- data/spec/all.rb +6 -0
- data/spec/base58_spec.rb +83 -0
- data/spec/block_header_spec.rb +18 -0
- data/spec/block_spec.rb +18 -0
- data/spec/currency_formatter_spec.rb +46 -0
- data/spec/data_spec.rb +50 -0
- data/spec/diagnostics_spec.rb +41 -0
- data/spec/key_spec.rb +205 -0
- data/spec/keychain_spec.rb +261 -0
- data/spec/network_spec.rb +48 -0
- data/spec/open_assets/asset_address_spec.rb +33 -0
- data/spec/open_assets/asset_id_spec.rb +15 -0
- data/spec/open_assets/asset_marker_spec.rb +47 -0
- data/spec/open_assets/asset_processor_spec.rb +567 -0
- data/spec/open_assets/asset_transaction_builder_spec.rb +273 -0
- data/spec/open_assets/asset_transaction_spec.rb +70 -0
- data/spec/proof_of_work_spec.rb +53 -0
- data/spec/script_spec.rb +66 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/transaction_builder_spec.rb +338 -0
- data/spec/transaction_spec.rb +162 -0
- data/spec/wire_format_spec.rb +283 -0
- metadata +141 -7
@@ -0,0 +1,206 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
describe BTC::Address do
|
3
|
+
|
4
|
+
it "should decode/encode mainnet pay-to-pubkey-hash address" do
|
5
|
+
address = BTC::Address.parse("19FGfswVqxNubJbh1NW8A4t51T9x9RDVWQ")
|
6
|
+
address.is_a?(BTC::PublicKeyAddress).must_equal(true)
|
7
|
+
|
8
|
+
address.mainnet?.must_equal true
|
9
|
+
address.testnet?.must_equal false
|
10
|
+
address.p2sh?.must_equal false
|
11
|
+
address.p2pkh?.must_equal true
|
12
|
+
|
13
|
+
address.data.must_equal "5a73e920b7836c74f9e740a5bb885e8580557038".from_hex
|
14
|
+
|
15
|
+
address = BTC::PublicKeyAddress.new(hash: "5a73e920b7836c74f9e740a5bb885e8580557038".from_hex)
|
16
|
+
|
17
|
+
address.script.to_s.must_equal "OP_DUP OP_HASH160 5a73e920b7836c74f9e740a5bb885e8580557038 OP_EQUALVERIFY OP_CHECKSIG"
|
18
|
+
|
19
|
+
address.to_s.must_equal("19FGfswVqxNubJbh1NW8A4t51T9x9RDVWQ")
|
20
|
+
address.data.must_equal(BTC::Data.data_from_hex("5a73e920b7836c74f9e740a5bb885e8580557038"))
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should decode/encode testnet pay-to-pubkey-hash address" do
|
24
|
+
|
25
|
+
address = BTC::Address.parse("mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn")
|
26
|
+
address.is_a?(BTC::PublicKeyAddress).must_equal true
|
27
|
+
|
28
|
+
address.mainnet?.must_equal false
|
29
|
+
address.testnet?.must_equal true
|
30
|
+
address.p2sh?.must_equal false
|
31
|
+
address.p2pkh?.must_equal true
|
32
|
+
|
33
|
+
address.data.must_equal "243f1394f44554f4ce3fd68649c19adc483ce924".from_hex
|
34
|
+
|
35
|
+
address2 = BTC::PublicKeyAddress.new(hash: "243f1394f44554f4ce3fd68649c19adc483ce924".from_hex, network: Network.testnet)
|
36
|
+
|
37
|
+
address2.to_s.must_equal("mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn")
|
38
|
+
address2.data.must_equal("243f1394f44554f4ce3fd68649c19adc483ce924".from_hex)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should detect invalid pay-to-pubkey-hash address" do
|
42
|
+
lambda { BTC::Address.parse(nil) }.must_raise ArgumentError
|
43
|
+
lambda { BTC::Address.parse("") }.must_raise FormatError
|
44
|
+
lambda { BTC::Address.parse("18FGfswVqxNubJbh1NW8A4t51T9x9RDVWQ") }.must_raise FormatError
|
45
|
+
lambda { BTC::Address.parse("19FGfswVqxNubJbh1NW8A4t51T9x9RDvwq") }.must_raise FormatError
|
46
|
+
lambda { BTC::Address.parse("19FGfswVqxNubJbh1NW8A4t51T9x9RD") }.must_raise FormatError
|
47
|
+
lambda { BTC::Address.parse("mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRf") }.must_raise FormatError
|
48
|
+
lambda { BTC::Address.parse("m") }.must_raise FormatError
|
49
|
+
lambda { BTC::Address.parse("mipc") }.must_raise FormatError
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should decode/encode mainnet pay-to-script-hash address" do
|
53
|
+
|
54
|
+
address = BTC::Address.parse("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX")
|
55
|
+
address.is_a?(BTC::ScriptHashAddress).must_equal(true)
|
56
|
+
|
57
|
+
address.mainnet?.must_equal true
|
58
|
+
address.testnet?.must_equal false
|
59
|
+
address.p2sh?.must_equal true
|
60
|
+
address.p2pkh?.must_equal false
|
61
|
+
|
62
|
+
address.data.must_equal "8f55563b9a19f321c211e9b9f38cdf686ea07845".from_hex
|
63
|
+
address.hash.must_equal "8f55563b9a19f321c211e9b9f38cdf686ea07845".from_hex
|
64
|
+
|
65
|
+
address = BTC::ScriptHashAddress.new(hash: "8f55563b9a19f321c211e9b9f38cdf686ea07845".from_hex)
|
66
|
+
|
67
|
+
address.script.to_s.must_equal "OP_HASH160 8f55563b9a19f321c211e9b9f38cdf686ea07845 OP_EQUAL"
|
68
|
+
|
69
|
+
address.to_s.must_equal("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX")
|
70
|
+
address.data.must_equal("8f55563b9a19f321c211e9b9f38cdf686ea07845".from_hex)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should decode/encode testnet pay-to-script-hash address" do
|
74
|
+
|
75
|
+
address = BTC::Address.parse("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX")
|
76
|
+
address.is_a?(BTC::ScriptHashAddress).must_equal(true)
|
77
|
+
|
78
|
+
address.mainnet?.must_equal true
|
79
|
+
address.testnet?.must_equal false
|
80
|
+
address.p2sh?.must_equal true
|
81
|
+
address.p2pkh?.must_equal false
|
82
|
+
|
83
|
+
address.data.must_equal "8f55563b9a19f321c211e9b9f38cdf686ea07845".from_hex
|
84
|
+
|
85
|
+
address = BTC::ScriptHashAddress.new(hash: "8f55563b9a19f321c211e9b9f38cdf686ea07845".from_hex)
|
86
|
+
|
87
|
+
address.to_s.must_equal("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX")
|
88
|
+
address.data.must_equal("8f55563b9a19f321c211e9b9f38cdf686ea07845".from_hex)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should detect invalid pay-to-script-hash address" do
|
92
|
+
lambda { BTC::Address.parse("3ektnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX") }.must_raise FormatError
|
93
|
+
lambda { BTC::Address.parse("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzqX") }.must_raise FormatError
|
94
|
+
lambda { BTC::Address.parse("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSg") }.must_raise FormatError
|
95
|
+
lambda { BTC::Address.parse("2mzQwSSnBHWHqSAqtTVQ6v47XtaisrJa1Vc") }.must_raise FormatError
|
96
|
+
lambda { BTC::Address.parse("2MzQwSSnBHWHqSAqtTVQ6v47XtaisrJa1vc") }.must_raise FormatError
|
97
|
+
lambda { BTC::Address.parse("2MzQwSSnBHWHqSAqtTVQ6v47XtaisrJ") }.must_raise FormatError
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
it "should decode/encode private key string with uncompressed pubkey" do
|
102
|
+
|
103
|
+
address = BTC::Address.parse("5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS")
|
104
|
+
address.is_a?(BTC::WIF).must_equal(true)
|
105
|
+
|
106
|
+
address.public_key_compressed?.must_equal false
|
107
|
+
address.mainnet?.must_equal true
|
108
|
+
address.testnet?.must_equal false
|
109
|
+
address.p2sh?.must_equal false
|
110
|
+
address.p2pkh?.must_equal false
|
111
|
+
|
112
|
+
address.data.must_equal "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex
|
113
|
+
|
114
|
+
address = BTC::WIF.new(private_key: "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex)
|
115
|
+
|
116
|
+
address.to_s.must_equal("5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS")
|
117
|
+
address.data.must_equal("c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex)
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should decode/encode private key string with compressed pubkey" do
|
122
|
+
|
123
|
+
address = BTC::Address.parse("L3p8oAcQTtuokSCRHQ7i4MhjWc9zornvpJLfmg62sYpLRJF9woSu")
|
124
|
+
address.is_a?(BTC::WIF).must_equal(true)
|
125
|
+
|
126
|
+
address.public_key_compressed?.must_equal true
|
127
|
+
address.mainnet?.must_equal true
|
128
|
+
address.testnet?.must_equal false
|
129
|
+
address.p2sh?.must_equal false
|
130
|
+
address.p2pkh?.must_equal false
|
131
|
+
|
132
|
+
address.data.must_equal "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex
|
133
|
+
|
134
|
+
address = BTC::WIF.new(private_key: "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex, public_key_compressed: true)
|
135
|
+
|
136
|
+
address.to_s.must_equal("L3p8oAcQTtuokSCRHQ7i4MhjWc9zornvpJLfmg62sYpLRJF9woSu")
|
137
|
+
address.data.must_equal("c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex)
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should detect invalid private key address" do
|
142
|
+
lambda { BTC::Address.parse("5kJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS") }.must_raise FormatError
|
143
|
+
lambda { BTC::Address.parse("5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hs") }.must_raise FormatError
|
144
|
+
lambda { BTC::Address.parse("5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZ") }.must_raise FormatError
|
145
|
+
lambda { BTC::Address.parse("L3P8oAcQTtuokSCRHQ7i4MhjWc9zornvpJLfmg62sYpLRJF9woSu") }.must_raise FormatError
|
146
|
+
lambda { BTC::Address.parse("L3p8oAcQTtuokSCRHQ7i4MhjWc9zornvpJLfmg62sYpLRJF9woSU") }.must_raise FormatError
|
147
|
+
lambda { BTC::Address.parse("L3p8oAcQTtuokSCRHQ7i4MhjWc9zornvpJLfmg62sYpLRJ") }.must_raise FormatError
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should convert strings and addresses into normalized address" do
|
151
|
+
BTC::Address.parse(BTC::Address.parse("19FGfswVqxNubJbh1NW8A4t51T9x9RDVWQ")).class.must_equal BTC::PublicKeyAddress
|
152
|
+
BTC::Address.parse("19FGfswVqxNubJbh1NW8A4t51T9x9RDVWQ").class.must_equal BTC::PublicKeyAddress
|
153
|
+
->{ BTC::Address.parse(nil) }.must_raise ArgumentError
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should convert any address to a public_address" do
|
157
|
+
a1 = BTC::Address.parse("1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8")
|
158
|
+
a1.public_address.must_equal a1
|
159
|
+
|
160
|
+
a2 = BTC::Address.parse("L3p8oAcQTtuokSCRHQ7i4MhjWc9zornvpJLfmg62sYpLRJF9woSu")
|
161
|
+
a2.public_address.must_equal a1
|
162
|
+
|
163
|
+
a3 = BTC::Address.parse("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX")
|
164
|
+
a3.public_address.must_equal a3
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should support equality" do
|
168
|
+
address1 = BTC::Address.parse("19FGfswVqxNubJbh1NW8A4t51T9x9RDVWQ")
|
169
|
+
address2 = BTC::PublicKeyAddress.new(hash: "5a73e920b7836c74f9e740a5bb885e8580557038".from_hex)
|
170
|
+
address3 = BTC::PublicKeyAddress.new(hash: "5a73e920b7836c74f9e740a5bb885e8580557038".from_hex, network: BTC::Network.testnet)
|
171
|
+
address4 = BTC::WIF.new(private_key: "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex, public_key_compressed: true)
|
172
|
+
address41 = BTC::WIF.new(private_key: "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex, public_key_compressed: true)
|
173
|
+
address5 = BTC::WIF.new(private_key: "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex, public_key_compressed: false)
|
174
|
+
address51 = BTC::WIF.new(private_key: "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex, public_key_compressed: false)
|
175
|
+
|
176
|
+
(address1 == address2).must_equal true
|
177
|
+
(address2 == address1).must_equal true
|
178
|
+
(address1 == address3).must_equal false
|
179
|
+
(address2 == address3).must_equal false
|
180
|
+
|
181
|
+
(address1 == address4).must_equal false
|
182
|
+
(address2 == address4).must_equal false
|
183
|
+
(address3 == address4).must_equal false
|
184
|
+
(address5 == address4).must_equal false
|
185
|
+
(address4 == address5).must_equal false
|
186
|
+
|
187
|
+
(address4 == address41).must_equal true
|
188
|
+
(address5 == address51).must_equal true
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should detect if wrong subclass is used when parsing an address" do
|
192
|
+
btc_addr_string = "19FGfswVqxNubJbh1NW8A4t51T9x9RDVWQ"
|
193
|
+
asset_addr_string = "akB4NBW9UuCmHuepksob6yfZs6naHtRCPNy"
|
194
|
+
btc_addr = Address.parse(btc_addr_string)
|
195
|
+
asset_addr = Address.parse(asset_addr_string)
|
196
|
+
|
197
|
+
->{ BTC::AssetAddress.parse(btc_addr_string) }.must_raise ArgumentError
|
198
|
+
->{ BTC::AssetAddress.parse(btc_addr) }.must_raise ArgumentError
|
199
|
+
|
200
|
+
->{ BTC::BitcoinPaymentAddress.parse(asset_addr_string) }.must_raise ArgumentError
|
201
|
+
->{ BTC::BitcoinPaymentAddress.parse(asset_addr) }.must_raise ArgumentError
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
|
206
|
+
|
data/spec/all.rb
ADDED
data/spec/base58_spec.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
describe BTC::Base58 do
|
3
|
+
|
4
|
+
def check_invalid_base58(base58_string, expected_class = BTC::FormatError)
|
5
|
+
lambda { Base58.data_from_base58(base58_string) }.must_raise expected_class
|
6
|
+
end
|
7
|
+
|
8
|
+
def check_invalid_base58check(base58check_string, expected_class = BTC::FormatError)
|
9
|
+
lambda { Base58.data_from_base58check(base58check_string) }.must_raise expected_class
|
10
|
+
end
|
11
|
+
|
12
|
+
def check_valid_base58(hex_string, base58_string)
|
13
|
+
# Convert to Base58
|
14
|
+
Base58.base58_from_data(BTC::Data.data_from_hex(hex_string)).must_equal(base58_string)
|
15
|
+
|
16
|
+
# Convert from Base58
|
17
|
+
BTC::Data.hex_from_data(Base58.data_from_base58(base58_string)).must_equal(hex_string)
|
18
|
+
end
|
19
|
+
|
20
|
+
def check_valid_base58check(hex, string)
|
21
|
+
# Convert to Base58Check
|
22
|
+
Base58.base58check_from_data(BTC::Data.data_from_hex(hex)).must_equal(string)
|
23
|
+
|
24
|
+
# Convert from Base58Check
|
25
|
+
BTC::Data.hex_from_data(Base58.data_from_base58check(string)).must_equal(hex)
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "Base58" do
|
29
|
+
it "should handle valid input" do
|
30
|
+
|
31
|
+
lambda { Base58.data_from_base58(nil) }.must_raise ArgumentError
|
32
|
+
lambda { Base58.base58_from_data(nil) }.must_raise ArgumentError
|
33
|
+
check_valid_base58("", "")
|
34
|
+
check_valid_base58("13", "L")
|
35
|
+
check_valid_base58("2e", "o")
|
36
|
+
check_valid_base58("61", "2g")
|
37
|
+
check_valid_base58("626262", "a3gV")
|
38
|
+
check_valid_base58("636363", "aPEr")
|
39
|
+
check_valid_base58("73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2")
|
40
|
+
check_valid_base58("00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L")
|
41
|
+
check_valid_base58("516b6fcd0f", "ABnLTmg")
|
42
|
+
check_valid_base58("bf4f89001e670274dd", "3SEo3LWLoPntC")
|
43
|
+
check_valid_base58("572e4794", "3EFU7m")
|
44
|
+
check_valid_base58("ecac89cad93923c02321", "EJDM8drfXA6uyA")
|
45
|
+
check_valid_base58("10c8511e", "Rt5zm")
|
46
|
+
check_valid_base58("00000000000000000000", "1111111111")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should handle invalid input" do
|
50
|
+
check_invalid_base58(nil, ArgumentError);
|
51
|
+
check_invalid_base58(" ");
|
52
|
+
check_invalid_base58("lLoO");
|
53
|
+
check_invalid_base58("l");
|
54
|
+
check_invalid_base58("O");
|
55
|
+
check_invalid_base58("öまи");
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "Base58Check" do
|
60
|
+
|
61
|
+
it "should handle valid input" do
|
62
|
+
check_valid_base58check("", "3QJmnh")
|
63
|
+
check_valid_base58check("007ab89f9fae3f8043dcee5f7b5467a0f0a6e2f7e1", "1CBtcGivXmHQ8ZqdPgeMfcpQNJrqTrSAcG")
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should handle invalid input" do
|
67
|
+
check_invalid_base58check(nil, ArgumentError);
|
68
|
+
check_invalid_base58check(" ");
|
69
|
+
check_invalid_base58check("lLoO");
|
70
|
+
check_invalid_base58check("l");
|
71
|
+
check_invalid_base58check("O");
|
72
|
+
check_invalid_base58check("öまи");
|
73
|
+
end
|
74
|
+
it "should detect incorrect checksum" do
|
75
|
+
check_invalid_base58check("L");
|
76
|
+
check_invalid_base58check("o");
|
77
|
+
check_invalid_base58check("0CBtcGivXmHQ8ZqdPgeMfcpQNJrqTrSAcG");
|
78
|
+
check_invalid_base58check("2CBtcGivXmHQ8ZqdPgeMfcpQNJrqTrSAcG");
|
79
|
+
check_invalid_base58check("11BtcGivXmHQ8ZqdPgeMfcpQNJrqTrSAcG");
|
80
|
+
check_invalid_base58check("1CBtcGivXmHQ8ZqdPgeMfcpQNJrqTrSAbG");
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
describe BTC::BlockHeader do
|
3
|
+
|
4
|
+
describe "Genesis Mainnet" do
|
5
|
+
it "should have a correct hash" do
|
6
|
+
BlockHeader.genesis_mainnet.block_id.must_equal "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
|
7
|
+
BlockHeader.genesis_mainnet.height.must_equal 0
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "Genesis Testnet" do
|
12
|
+
it "should have a correct hash" do
|
13
|
+
BlockHeader.genesis_testnet.block_id.must_equal "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
|
14
|
+
BlockHeader.genesis_testnet.height.must_equal 0
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/spec/block_spec.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
describe BTC::Block do
|
3
|
+
|
4
|
+
describe "Genesis Mainnet" do
|
5
|
+
it "should have a correct hash" do
|
6
|
+
Block.genesis_mainnet.block_id.must_equal "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
|
7
|
+
Block.genesis_mainnet.height.must_equal 0
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "Genesis Testnet" do
|
12
|
+
it "should have a correct hash" do
|
13
|
+
Block.genesis_testnet.block_id.must_equal "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
|
14
|
+
Block.genesis_testnet.height.must_equal 0
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe BTC::CurrencyFormatter do
|
4
|
+
|
5
|
+
it "should support normal bitcoin formatting" do
|
6
|
+
fm = BTC::CurrencyFormatter.btc_formatter
|
7
|
+
|
8
|
+
fm.string_from_number(1*COIN).must_equal("1.0")
|
9
|
+
fm.string_from_number(42*COIN).must_equal("42.0")
|
10
|
+
fm.string_from_number(42000*COIN).must_equal("42000.0")
|
11
|
+
fm.string_from_number(42000*COIN + 123).must_equal("42000.00000123")
|
12
|
+
fm.string_from_number(42000*COIN + 123000).must_equal("42000.00123")
|
13
|
+
fm.string_from_number(42000*COIN + 123456).must_equal("42000.00123456")
|
14
|
+
fm.string_from_number(42000*COIN + COIN/2).must_equal("42000.5")
|
15
|
+
|
16
|
+
fm.number_from_string("1").must_equal 1*COIN
|
17
|
+
fm.number_from_string("1.").must_equal 1*COIN
|
18
|
+
fm.number_from_string("1.0").must_equal 1*COIN
|
19
|
+
fm.number_from_string("42").must_equal 42*COIN
|
20
|
+
fm.number_from_string("42.123").must_equal 42*COIN + 12300000
|
21
|
+
fm.number_from_string("42.12345678").must_equal 42*COIN + 12345678
|
22
|
+
fm.number_from_string("42.10000000").must_equal 42*COIN + 10000000
|
23
|
+
fm.number_from_string("42.10000").must_equal 42*COIN + 10000000
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should support long bitcoin formatting" do
|
27
|
+
fm = BTC::CurrencyFormatter.btc_long_formatter
|
28
|
+
|
29
|
+
fm.string_from_number(1*COIN).must_equal("1.00000000")
|
30
|
+
fm.string_from_number(42*COIN).must_equal("42.00000000")
|
31
|
+
fm.string_from_number(42000*COIN).must_equal("42000.00000000")
|
32
|
+
fm.string_from_number(42000*COIN + 123).must_equal("42000.00000123")
|
33
|
+
fm.string_from_number(42000*COIN + 123000).must_equal("42000.00123000")
|
34
|
+
fm.string_from_number(42000*COIN + 123456).must_equal("42000.00123456")
|
35
|
+
fm.string_from_number(42000*COIN + COIN/2).must_equal("42000.50000000")
|
36
|
+
|
37
|
+
fm.number_from_string("1").must_equal 1*COIN
|
38
|
+
fm.number_from_string("1.").must_equal 1*COIN
|
39
|
+
fm.number_from_string("1.0").must_equal 1*COIN
|
40
|
+
fm.number_from_string("42").must_equal 42*COIN
|
41
|
+
fm.number_from_string("42.123").must_equal 42*COIN + 12300000
|
42
|
+
fm.number_from_string("42.12345678").must_equal 42*COIN + 12345678
|
43
|
+
fm.number_from_string("42.10000000").must_equal 42*COIN + 10000000
|
44
|
+
fm.number_from_string("42.10000").must_equal 42*COIN + 10000000
|
45
|
+
end
|
46
|
+
end
|
data/spec/data_spec.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe BTC::Data do
|
4
|
+
|
5
|
+
it "should decode valid hex" do
|
6
|
+
lambda { BTC::Data.data_from_hex(nil) }.must_raise ArgumentError
|
7
|
+
BTC::Data.data_from_hex("fe").bytes.must_equal "\xfe".bytes
|
8
|
+
BTC::Data.data_from_hex("deadBEEF").bytes.must_equal "\xde\xad\xbe\xef".bytes
|
9
|
+
BTC::Data.data_from_hex(" \r\n\tdeadBEEF \t \r \n").bytes.must_equal "\xde\xad\xbe\xef".bytes
|
10
|
+
BTC::Data.data_from_hex("").bytes.must_equal "".bytes
|
11
|
+
BTC::Data.data_from_hex(" \t ").bytes.must_equal "".bytes
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should not decode invalid hex" do
|
15
|
+
lambda { BTC::Data.data_from_hex("f") }.must_raise FormatError
|
16
|
+
lambda { BTC::Data.data_from_hex("dxadBEEF") }.must_raise FormatError
|
17
|
+
lambda { BTC::Data.data_from_hex("-") }.must_raise FormatError
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should encode valid hex" do
|
21
|
+
lambda { BTC::Data.hex_from_data(nil) }.must_raise ArgumentError
|
22
|
+
BTC::Data.hex_from_data("\xfe").bytes.must_equal "fe".bytes
|
23
|
+
BTC::Data.hex_from_data("\xde\xad\xbe\xef").bytes.must_equal "deadbeef".bytes
|
24
|
+
BTC::Data.hex_from_data("").bytes.must_equal "".bytes
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should encode bytes" do
|
28
|
+
BTC::Data.bytes_from_data("Hello, world").must_equal "Hello, world".bytes
|
29
|
+
BTC::Data.bytes_from_data("Hello, world").must_equal [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100]
|
30
|
+
BTC::Data.data_from_bytes([72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100]).must_equal "Hello, world"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should access ranges of bytes" do
|
34
|
+
BTC::Data.bytes_from_data("Hello, world", offset: 1).must_equal "ello, world".bytes
|
35
|
+
BTC::Data.bytes_from_data("Hello, world", offset: 0, limit: 3).must_equal "Hel".bytes
|
36
|
+
|
37
|
+
# Range takes precedence over offset/limit.
|
38
|
+
BTC::Data.bytes_from_data("Hello, world", offset: 0, limit: 3, range: 1..2).must_equal "el".bytes
|
39
|
+
|
40
|
+
BTC::Data.bytes_from_data("Hello, world", range: 1..3).must_equal "ell".bytes
|
41
|
+
BTC::Data.bytes_from_data("Hello, world", range: 1...3).must_equal "el".bytes
|
42
|
+
|
43
|
+
# Outside bounds
|
44
|
+
BTC::Data.bytes_from_data("Hello, world", offset: 110, limit: 3).must_equal []
|
45
|
+
BTC::Data.bytes_from_data("Hello, world", offset: 0, limit: 0).must_equal []
|
46
|
+
BTC::Data.bytes_from_data("Hello, world", range: 100..101).must_equal []
|
47
|
+
BTC::Data.bytes_from_data("Hello, world", range: 0...0).must_equal []
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe BTC::Diagnostics do
|
4
|
+
|
5
|
+
it "should record messages" do
|
6
|
+
|
7
|
+
BTC::Diagnostics.current.wont_be_nil
|
8
|
+
|
9
|
+
# Due to other tests this may not be nil, so we should not check for it.
|
10
|
+
# We also should not clear the state in order to test our recording code against whatever state was there before.
|
11
|
+
# BTC::Diagnostics.current.last_message.must_equal nil
|
12
|
+
|
13
|
+
BTC::Diagnostics.current.add_message("msg1")
|
14
|
+
BTC::Diagnostics.current.last_message.must_equal "msg1"
|
15
|
+
BTC::Diagnostics.current.add_message("msg2")
|
16
|
+
BTC::Diagnostics.current.last_message.must_equal "msg2"
|
17
|
+
|
18
|
+
BTC::Diagnostics.current.record do
|
19
|
+
|
20
|
+
BTC::Diagnostics.current.record do
|
21
|
+
BTC::Diagnostics.current.add_message("a")
|
22
|
+
BTC::Diagnostics.current.add_message("b")
|
23
|
+
BTC::Diagnostics.current.last_message.must_equal "b"
|
24
|
+
end.map(&:to_s).must_equal ["a", "b"]
|
25
|
+
|
26
|
+
BTC::Diagnostics.current.last_message.must_equal "b"
|
27
|
+
|
28
|
+
BTC::Diagnostics.current.add_message("c")
|
29
|
+
|
30
|
+
BTC::Diagnostics.current.record do
|
31
|
+
BTC::Diagnostics.current.add_message("d")
|
32
|
+
BTC::Diagnostics.current.add_message("e")
|
33
|
+
end.map(&:to_s).must_equal ["d", "e"]
|
34
|
+
|
35
|
+
end.map(&:to_s).must_equal ["a", "b", "c", "d", "e"]
|
36
|
+
|
37
|
+
BTC::Diagnostics.current.last_message.must_equal "e"
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|