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,273 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe BTC::AssetTransactionBuilder do
|
4
|
+
|
5
|
+
class SignerByKey
|
6
|
+
include TransactionBuilder::Signer
|
7
|
+
def initialize(&block)
|
8
|
+
@block = block
|
9
|
+
end
|
10
|
+
def signing_key_for_output(output: nil, address: nil)
|
11
|
+
@block.call(output, address)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "Issuing an asset with two transactions" do
|
16
|
+
|
17
|
+
before do
|
18
|
+
builder = BTC::AssetTransactionBuilder.new
|
19
|
+
|
20
|
+
@all_wallet_utxos = self.mock_wallet_utxos
|
21
|
+
builder.bitcoin_provider = TransactionBuilder::Provider.new do |txb|
|
22
|
+
@all_wallet_utxos
|
23
|
+
end
|
24
|
+
builder.signer = SignerByKey.new do |output, address|
|
25
|
+
mock_all_keys.find{|k| k.address == address }
|
26
|
+
end
|
27
|
+
|
28
|
+
# We want to issue 1M units to one address and 50K units for another.
|
29
|
+
# OpenAssets does not allow issuing different assets in one Asset Transaction because Asset ID is determined by the first input.
|
30
|
+
builder.issue_asset(source_script: issuer1_key.address.script, amount: 1000_000, address: holder1_asset_address)
|
31
|
+
builder.issue_asset(source_script: issuer1_key.address.script, amount: 50_000, address: holder2_asset_address)
|
32
|
+
|
33
|
+
# Just some payment to add.
|
34
|
+
builder.send_bitcoin(amount: 100, address: wallet1_key.address)
|
35
|
+
|
36
|
+
# Send btc change to this address.
|
37
|
+
builder.bitcoin_change_address = wallet2_key.address
|
38
|
+
|
39
|
+
# Send leftover assets to this address.
|
40
|
+
builder.asset_change_address = holder2_asset_address
|
41
|
+
|
42
|
+
# Build transactions.
|
43
|
+
@builder = builder
|
44
|
+
@result = builder.build
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should have two transactions: asset definition and issuance" do
|
48
|
+
@result.transactions.size.must_equal(2)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should have last transaction wrapped in AssetTransaction" do
|
52
|
+
@result.asset_transaction.transaction.must_equal(@result.transactions.last)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should have two transactions linked up" do
|
56
|
+
@result.transactions.last.inputs.first.previous_hash.must_equal @result.transactions.first.transaction_hash
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should have first transaction uncolored" do
|
60
|
+
@result.transactions.first.open_assets_transaction?.must_equal false
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should have second transaction with colored outputs" do
|
64
|
+
@result.transactions.last.open_assets_transaction?.must_equal true
|
65
|
+
@result.asset_transaction.inputs.each do |ain|
|
66
|
+
ain.colored?.must_equal false
|
67
|
+
ain.verified?.must_equal true
|
68
|
+
end
|
69
|
+
@result.asset_transaction.outputs.each_with_index do |aout, i|
|
70
|
+
aout.colored?.must_equal(i < 2) # only first 2 outputs are colored because they issue asset
|
71
|
+
aout.verified?.must_equal true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should have an asset cost of two issuances" do
|
76
|
+
@result.assets_cost.must_equal 546*2
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "Issuing an asset with an existing source output" do
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "Transferring a few assets" do
|
84
|
+
before do
|
85
|
+
|
86
|
+
builder = BTC::AssetTransactionBuilder.new
|
87
|
+
|
88
|
+
@all_wallet_utxos = self.mock_wallet_utxos
|
89
|
+
builder.bitcoin_provider = TransactionBuilder::Provider.new do |txb|
|
90
|
+
@all_wallet_utxos
|
91
|
+
end
|
92
|
+
builder.signer = SignerByKey.new do |output, address|
|
93
|
+
mock_all_keys.find{|k| k.address == address }
|
94
|
+
end
|
95
|
+
|
96
|
+
# We want to be able to swap assets: when one user provides Apples and the other provides Oranges.
|
97
|
+
# Each transfer may have its own unspents and its own change address.
|
98
|
+
# If those are not specified, a per-builder setting is chosen.
|
99
|
+
|
100
|
+
@asset1 = AssetID.new(script: Script.new << OP_1)
|
101
|
+
@asset2 = AssetID.new(script: Script.new << OP_2)
|
102
|
+
|
103
|
+
builder.transfer_asset(
|
104
|
+
asset_id: @asset1,
|
105
|
+
amount: 10_000,
|
106
|
+
address: holder2_asset_address,
|
107
|
+
unspent_outputs: [
|
108
|
+
AssetTransactionOutput.new(
|
109
|
+
transaction_output: mock_utxo(value: 1000),
|
110
|
+
asset_id: @asset1,
|
111
|
+
value: 11_000,
|
112
|
+
transfer: true,
|
113
|
+
verified: true,
|
114
|
+
)
|
115
|
+
],
|
116
|
+
change_address: holder1_asset_address
|
117
|
+
)
|
118
|
+
|
119
|
+
builder.transfer_asset(
|
120
|
+
asset_id: @asset2,
|
121
|
+
amount: 50_000,
|
122
|
+
address: holder1_asset_address,
|
123
|
+
unspent_outputs: [
|
124
|
+
AssetTransactionOutput.new(
|
125
|
+
transaction_output: mock_utxo(value: 1000),
|
126
|
+
asset_id: @asset2,
|
127
|
+
value: 150_000,
|
128
|
+
transfer: true,
|
129
|
+
verified: true,
|
130
|
+
)
|
131
|
+
],
|
132
|
+
change_address: holder2_asset_address
|
133
|
+
)
|
134
|
+
|
135
|
+
# Send btc change to this address.
|
136
|
+
builder.bitcoin_change_address = wallet2_key.address
|
137
|
+
|
138
|
+
# Send leftover assets to this address.
|
139
|
+
builder.asset_change_address = AssetAddress.new(bitcoin_address: holder2_key.address)
|
140
|
+
|
141
|
+
# Build transactions.
|
142
|
+
@builder = builder
|
143
|
+
@result = builder.build
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should have two change outputs: for each transfer" do
|
147
|
+
@result.asset_transaction.outputs.size.must_equal(1 + 2 + 2 + 1)
|
148
|
+
marker, transfer1, change1, transfer2, change2, btcchange = @result.asset_transaction.outputs
|
149
|
+
|
150
|
+
transfer1.transfer?.must_equal true
|
151
|
+
transfer1.value.must_equal 10_000
|
152
|
+
change1.transfer?.must_equal true
|
153
|
+
change1.value.must_equal 1_000
|
154
|
+
transfer1.asset_id.to_s.must_equal change1.asset_id.to_s
|
155
|
+
transfer1.asset_id.to_s.must_equal @asset1.to_s
|
156
|
+
transfer1.transaction_output.script.standard_address.to_s.must_equal holder2_key.address.to_s
|
157
|
+
change1.transaction_output.script.standard_address.to_s.must_equal holder1_key.address.to_s
|
158
|
+
|
159
|
+
transfer2.transfer?.must_equal true
|
160
|
+
transfer2.value.must_equal 50_000
|
161
|
+
change2.transfer?.must_equal true
|
162
|
+
change2.value.must_equal 100_000
|
163
|
+
transfer2.asset_id.to_s.must_equal change2.asset_id.to_s
|
164
|
+
transfer2.asset_id.to_s.must_equal @asset2.to_s
|
165
|
+
transfer2.transaction_output.script.standard_address.to_s.must_equal holder1_key.address.to_s
|
166
|
+
change2.transaction_output.script.standard_address.to_s.must_equal holder2_key.address.to_s
|
167
|
+
|
168
|
+
btcchange.colored?.must_equal false
|
169
|
+
btcchange.verified?.must_equal true
|
170
|
+
btcchange.asset_id.must_equal nil
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Mocked wallet
|
175
|
+
|
176
|
+
def wallet1_key
|
177
|
+
@wallet1_key ||= Key.new(private_key: "Wallet1".sha256)
|
178
|
+
end
|
179
|
+
|
180
|
+
def wallet2_key
|
181
|
+
@wallet2_key ||= Key.new(private_key: "Wallet2".sha256)
|
182
|
+
end
|
183
|
+
|
184
|
+
def issuer1_key
|
185
|
+
@issuer1_key ||= Key.new(private_key: "Issuer1".sha256)
|
186
|
+
end
|
187
|
+
|
188
|
+
def issuer2_key
|
189
|
+
@issuer2_key ||= Key.new(private_key: "Issuer2".sha256)
|
190
|
+
end
|
191
|
+
|
192
|
+
def holder1_key
|
193
|
+
@holder1_key ||= Key.new(private_key: "Holder1".sha256)
|
194
|
+
end
|
195
|
+
|
196
|
+
def holder2_key
|
197
|
+
@holder2_key ||= Key.new(private_key: "Holder2".sha256)
|
198
|
+
end
|
199
|
+
|
200
|
+
def holder1_asset_address
|
201
|
+
AssetAddress.new(bitcoin_address: holder1_key.address)
|
202
|
+
end
|
203
|
+
|
204
|
+
def holder2_asset_address
|
205
|
+
AssetAddress.new(bitcoin_address: holder2_key.address)
|
206
|
+
end
|
207
|
+
|
208
|
+
def mock_wallet_keys
|
209
|
+
@mock_wallet_keys ||= [wallet1_key, wallet2_key]
|
210
|
+
end
|
211
|
+
|
212
|
+
def mock_all_keys
|
213
|
+
@mock_all_keys ||= [wallet1_key, wallet2_key,
|
214
|
+
issuer1_key, issuer2_key,
|
215
|
+
holder1_key, holder2_key]
|
216
|
+
end
|
217
|
+
|
218
|
+
def mock_wallet_addresses
|
219
|
+
mock_wallet_keys.map{|k| k.address }
|
220
|
+
end
|
221
|
+
|
222
|
+
def mock_wallet_utxos
|
223
|
+
scripts = mock_wallet_addresses.map{|a| a.script }
|
224
|
+
(1..32).map do |i|
|
225
|
+
TransactionOutput.new(value: 100_000,
|
226
|
+
script: scripts[i % scripts.size],
|
227
|
+
transaction_hash: ((16+i).to_s(16)*32).from_hex,
|
228
|
+
index: i)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def mock_utxo(value: 100_000, index: 0, script: Script.new << OP_1)
|
233
|
+
TransactionOutput.new(value: value,
|
234
|
+
script: script,
|
235
|
+
transaction_hash: Key.random.private_key.sha256,
|
236
|
+
index: index)
|
237
|
+
end
|
238
|
+
|
239
|
+
def mock_asset_utxos
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
244
|
+
|
245
|
+
# Temporary test
|
246
|
+
describe "Issuing an asset" do
|
247
|
+
|
248
|
+
it "should issue a new asset from a given tx output" do
|
249
|
+
issuer = BTC::Key.new(private_key: "Treasury Key".sha256)
|
250
|
+
holder = BTC::Key.new(private_key: "Chancellor Key".sha256)
|
251
|
+
|
252
|
+
issuing_script = issuer.address.script
|
253
|
+
holding_script = holder.address.script
|
254
|
+
|
255
|
+
source_output = TransactionOutput.new(value: 100, script: issuing_script)
|
256
|
+
|
257
|
+
# These are set automatically if source_output is a part of some BTC::Transaction
|
258
|
+
# We need these to complete the input for the transfer transaction.
|
259
|
+
source_output.transaction_hash = BTC::Data.hash256("some tx")
|
260
|
+
source_output.index = 0
|
261
|
+
|
262
|
+
transfer = Transaction.new
|
263
|
+
transfer.add_input(TransactionInput.new(transaction_output: source_output))
|
264
|
+
transfer.add_output(TransactionOutput.new(value: source_output.value, script: holding_script))
|
265
|
+
marker = AssetMarker.new
|
266
|
+
marker.quantities = [ 1000_000_000 ]
|
267
|
+
marker.metadata = "Chancellor bailing out banks"
|
268
|
+
transfer.outputs << marker.output
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
|
273
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe "Serialization" do
|
4
|
+
|
5
|
+
def build_asset_transaction(inputs: [], issues: [], transfers: [])
|
6
|
+
tx = Transaction.new
|
7
|
+
script = PublicKeyAddress.new(hash: "some address".hash160).script
|
8
|
+
inputs.each do
|
9
|
+
tx.add_input(TransactionInput.new(previous_hash: "".sha256, previous_index: 0))
|
10
|
+
end
|
11
|
+
issues.each do |tuple|
|
12
|
+
tx.add_output(TransactionOutput.new(value: 1, script: script))
|
13
|
+
end
|
14
|
+
qtys = issues.map{|tuple| tuple.first} + transfers.map{|tuple| tuple.first}
|
15
|
+
tx.add_output(AssetMarker.new(quantities: qtys).output)
|
16
|
+
transfers.each do |tuple|
|
17
|
+
tx.add_output(TransactionOutput.new(value: 1, script: script))
|
18
|
+
end
|
19
|
+
|
20
|
+
atx = AssetTransaction.new(transaction: tx)
|
21
|
+
atx.inputs.each_with_index do |ain, i|
|
22
|
+
amount, name = inputs[i]
|
23
|
+
if amount
|
24
|
+
ain.asset_id = asset_id(name)
|
25
|
+
ain.value = amount
|
26
|
+
ain.verified = true
|
27
|
+
else
|
28
|
+
ain.asset_id = nil
|
29
|
+
ain.value = nil
|
30
|
+
ain.verified = true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
atx
|
35
|
+
end
|
36
|
+
|
37
|
+
def asset_id(name)
|
38
|
+
name ? AssetID.new(hash: name.hash160) : nil
|
39
|
+
end
|
40
|
+
|
41
|
+
before do
|
42
|
+
@atx = build_asset_transaction(
|
43
|
+
inputs: [ [100, "A"], [30, "B"], [14, "B"] ],
|
44
|
+
issues: [ ],
|
45
|
+
transfers: [ [40, "A"], [60, "A"], [44, "B"] ]
|
46
|
+
)
|
47
|
+
data = @atx.data
|
48
|
+
@atx2 = AssetTransaction.new(data: data)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should restore all outputs" do
|
52
|
+
@atx.inputs.each_with_index do |ain1, i|
|
53
|
+
ain2 = @atx2.inputs[i]
|
54
|
+
ain1.verified?.must_equal ain2.verified?
|
55
|
+
ain1.verified?.must_equal true
|
56
|
+
ain1.asset_id.must_equal ain2.asset_id
|
57
|
+
ain1.value.must_equal ain2.value
|
58
|
+
end
|
59
|
+
@atx.outputs.each_with_index do |aout1, i|
|
60
|
+
aout2 = @atx2.outputs[i]
|
61
|
+
aout1.verified?.must_equal aout2.verified?
|
62
|
+
aout1.verified?.must_equal aout1.marker?
|
63
|
+
aout1.asset_id.must_equal aout2.asset_id
|
64
|
+
aout1.asset_id.must_equal nil
|
65
|
+
aout1.value.must_equal aout2.value
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
describe BTC::ProofOfWork do
|
3
|
+
|
4
|
+
POW = BTC::ProofOfWork
|
5
|
+
|
6
|
+
it "should convert target to bits" do
|
7
|
+
POW.bits_from_target(0x00000000ffff0000000000000000000000000000000000000000000000000000).must_equal 0x1d00ffff
|
8
|
+
POW.bits_from_target(0x00000007fff80000000000000000000000000000000000000000000000000000).must_equal 0x1d07fff8
|
9
|
+
POW.bits_from_target(0x0).must_equal 0x03000000
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should convert bits to target" do
|
13
|
+
POW.target_from_bits(0x1d00ffff).must_equal 0x00000000ffff0000000000000000000000000000000000000000000000000000
|
14
|
+
POW.target_from_bits(0x1d07fff8).must_equal 0x00000007fff80000000000000000000000000000000000000000000000000000
|
15
|
+
POW.target_from_bits(0x03000000).must_equal 0x0
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should convert hash to target integer" do
|
19
|
+
POW.target_from_hash("").must_equal 0
|
20
|
+
POW.target_from_hash("\x00").must_equal 0
|
21
|
+
POW.target_from_hash("\x12").must_equal 0x12
|
22
|
+
POW.target_from_hash("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000".from_hex).must_equal 0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should convert target integer to 32-byte hash" do
|
26
|
+
POW.hash_from_target(0).must_equal "\x00"*32
|
27
|
+
POW.hash_from_target(0xbabe).must_equal "\xbe\xba".b.ljust(32, "\x00")
|
28
|
+
POW.hash_from_target(0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f).must_equal "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000".from_hex
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should convert target to difficulty (on mainnet)" do
|
32
|
+
POW.difficulty_from_target(0x00000000ffff0000000000000000000000000000000000000000000000000000).to_i.must_equal 1
|
33
|
+
POW.difficulty_from_target(0x000000007fff8000000000000000000000000000000000000000000000000000).to_i.must_equal 2
|
34
|
+
POW.difficulty_from_target(0x000000000ffff000000000000000000000000000000000000000000000000000).to_i.must_equal 16
|
35
|
+
POW.difficulty_from_target(0x0000000000ffff00000000000000000000000000000000000000000000000000).to_i.must_equal 256
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should convert target to difficulty (on testnet)" do
|
39
|
+
POW.difficulty_from_target(0x00000007fff80000000000000000000000000000000000000000000000000000,
|
40
|
+
max_target: POW::MAX_TARGET_TESTNET).to_i.must_equal 1
|
41
|
+
POW.difficulty_from_target(0x00000003fff80000000000000000000000000000000000000000000000000000,
|
42
|
+
max_target: POW::MAX_TARGET_TESTNET).to_i.must_equal 2
|
43
|
+
POW.difficulty_from_target(0x000000007fff8000000000000000000000000000000000000000000000000000,
|
44
|
+
max_target: POW::MAX_TARGET_TESTNET).to_i.must_equal 16
|
45
|
+
POW.difficulty_from_target(0x0000000007fff800000000000000000000000000000000000000000000000000,
|
46
|
+
max_target: POW::MAX_TARGET_TESTNET).to_i.must_equal 256
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should convert difficulty to target or bits" do
|
50
|
+
POW.target_from_difficulty(1.0).must_equal 0x00000000ffff0000000000000000000000000000000000000000000000000000
|
51
|
+
POW.bits_from_difficulty(39603666252.41841).must_equal 0x181bc330
|
52
|
+
end
|
53
|
+
end
|
data/spec/script_spec.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
describe BTC::Script do
|
3
|
+
|
4
|
+
it "should instantiate with empty data" do
|
5
|
+
empty_script = Script.new
|
6
|
+
empty_script.data.must_equal "".b
|
7
|
+
empty_script.to_s.must_equal ''
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should support standard P2PKH script" do
|
11
|
+
script = (Script.new << OP_DUP << OP_HASH160 << "5a73e920b7836c74f9e740a5bb885e8580557038".from_hex << OP_EQUALVERIFY << OP_CHECKSIG)
|
12
|
+
script.standard?.must_equal true
|
13
|
+
script.public_key_hash_script?.must_equal true
|
14
|
+
script.script_hash_script?.must_equal false
|
15
|
+
script.multisig_script?.must_equal false
|
16
|
+
script.standard_multisig_script?.must_equal false
|
17
|
+
script.standard_address.class.must_equal PublicKeyAddress
|
18
|
+
script.standard_address.data.must_equal "5a73e920b7836c74f9e740a5bb885e8580557038".from_hex
|
19
|
+
script.to_s.must_equal "OP_DUP OP_HASH160 5a73e920b7836c74f9e740a5bb885e8580557038 OP_EQUALVERIFY OP_CHECKSIG"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should support standard P2SH script" do
|
23
|
+
script = (Script.new << OP_HASH160 << "5a73e920b7836c74f9e740a5bb885e8580557038".from_hex << OP_EQUAL)
|
24
|
+
script.standard?.must_equal true
|
25
|
+
script.public_key_hash_script?.must_equal false
|
26
|
+
script.script_hash_script?.must_equal true
|
27
|
+
script.multisig_script?.must_equal false
|
28
|
+
script.standard_multisig_script?.must_equal false
|
29
|
+
script.standard_address.class.must_equal ScriptHashAddress
|
30
|
+
script.standard_address.data.must_equal "5a73e920b7836c74f9e740a5bb885e8580557038".from_hex
|
31
|
+
script.to_s.must_equal "OP_HASH160 5a73e920b7836c74f9e740a5bb885e8580557038 OP_EQUAL"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should support standard multisig script" do
|
35
|
+
script = (Script.new << OP_1 <<
|
36
|
+
"c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex <<
|
37
|
+
"bffbec99da8a6573bd4e359d85c8cb62e6f483d9afac4be2db963f0fe10bcb19".from_hex <<
|
38
|
+
OP_2 <<
|
39
|
+
OP_CHECKMULTISIG)
|
40
|
+
script.standard?.must_equal true
|
41
|
+
script.public_key_hash_script?.must_equal false
|
42
|
+
script.script_hash_script?.must_equal false
|
43
|
+
script.multisig_script?.must_equal true
|
44
|
+
script.standard_multisig_script?.must_equal true
|
45
|
+
script.standard_address.must_equal nil
|
46
|
+
script.multisig_public_keys.must_equal [
|
47
|
+
"c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex,
|
48
|
+
"bffbec99da8a6573bd4e359d85c8cb62e6f483d9afac4be2db963f0fe10bcb19".from_hex
|
49
|
+
]
|
50
|
+
script.multisig_signatures_required.must_equal 1
|
51
|
+
script.to_s.must_equal "OP_1 c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a "+
|
52
|
+
"bffbec99da8a6573bd4e359d85c8cb62e6f483d9afac4be2db963f0fe10bcb19 OP_2 OP_CHECKMULTISIG"
|
53
|
+
|
54
|
+
script2 = Script.multisig(public_keys:[
|
55
|
+
"c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a".from_hex,
|
56
|
+
"bffbec99da8a6573bd4e359d85c8cb62e6f483d9afac4be2db963f0fe10bcb19".from_hex
|
57
|
+
], signatures_required: 1)
|
58
|
+
|
59
|
+
script2.standard_multisig_script?.must_equal true
|
60
|
+
script.must_equal script2
|
61
|
+
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
end
|