bitcoin-ruby 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -1
- data/Gemfile +21 -0
- data/README.rdoc +85 -25
- data/Rakefile +7 -3
- data/bin/bitcoin_node +39 -42
- data/bin/bitcoin_shell +1 -0
- data/bin/bitcoin_wallet +129 -53
- data/bitcoin-ruby.gemspec +4 -7
- data/concept-examples/blockchain-pow.rb +1 -1
- data/doc/CONFIG.rdoc +5 -5
- data/doc/EXAMPLES.rdoc +9 -5
- data/doc/NAMECOIN.rdoc +34 -0
- data/doc/NODE.rdoc +147 -10
- data/examples/balance.rb +10 -4
- data/examples/bbe_verify_tx.rb +7 -2
- data/examples/forwarder.rb +73 -0
- data/examples/generate_tx.rb +34 -0
- data/examples/simple_network_monitor_and_util.rb +187 -0
- data/examples/verify_tx.rb +1 -1
- data/lib/bitcoin.rb +308 -18
- data/lib/bitcoin/builder.rb +62 -36
- data/lib/bitcoin/config.rb +2 -0
- data/lib/bitcoin/connection.rb +11 -8
- data/lib/bitcoin/electrum/mnemonic.rb +162 -0
- data/lib/bitcoin/ffi/openssl.rb +187 -21
- data/lib/bitcoin/gui/addr_view.rb +2 -0
- data/lib/bitcoin/gui/conn_view.rb +2 -0
- data/lib/bitcoin/gui/connection.rb +2 -0
- data/lib/bitcoin/gui/em_gtk.rb +2 -0
- data/lib/bitcoin/gui/gui.rb +2 -0
- data/lib/bitcoin/gui/helpers.rb +2 -0
- data/lib/bitcoin/gui/tree_view.rb +2 -0
- data/lib/bitcoin/gui/tx_view.rb +2 -0
- data/lib/bitcoin/key.rb +77 -11
- data/lib/bitcoin/litecoin.rb +81 -0
- data/lib/bitcoin/logger.rb +20 -1
- data/lib/bitcoin/namecoin.rb +279 -0
- data/lib/bitcoin/network/command_client.rb +7 -6
- data/lib/bitcoin/network/command_handler.rb +229 -43
- data/lib/bitcoin/network/connection_handler.rb +182 -70
- data/lib/bitcoin/network/node.rb +231 -106
- data/lib/bitcoin/protocol.rb +44 -23
- data/lib/bitcoin/protocol/address.rb +5 -3
- data/lib/bitcoin/protocol/alert.rb +3 -4
- data/lib/bitcoin/protocol/aux_pow.rb +123 -0
- data/lib/bitcoin/protocol/block.rb +98 -18
- data/lib/bitcoin/protocol/handler.rb +6 -5
- data/lib/bitcoin/protocol/parser.rb +44 -19
- data/lib/bitcoin/protocol/tx.rb +105 -52
- data/lib/bitcoin/protocol/txin.rb +39 -19
- data/lib/bitcoin/protocol/txout.rb +28 -13
- data/lib/bitcoin/protocol/version.rb +16 -7
- data/lib/bitcoin/script.rb +579 -122
- data/lib/bitcoin/storage/{dummy.rb → dummy/dummy_store.rb} +8 -14
- data/lib/bitcoin/storage/models.rb +20 -7
- data/lib/bitcoin/storage/{sequel_store/sequel_migrations.rb → sequel/migrations.rb} +22 -7
- data/lib/bitcoin/storage/sequel/migrations/001_base_schema.rb +52 -0
- data/lib/bitcoin/storage/sequel/migrations/002_tx.rb +50 -0
- data/lib/bitcoin/storage/sequel/migrations/003_change_txin_script_sig_to_blob.rb +18 -0
- data/lib/bitcoin/storage/sequel/sequel_store.rb +436 -0
- data/lib/bitcoin/storage/storage.rb +233 -28
- data/lib/bitcoin/storage/utxo/migrations/001_base_schema.rb +52 -0
- data/lib/bitcoin/storage/utxo/migrations/002_utxo.rb +18 -0
- data/lib/bitcoin/storage/utxo/utxo_store.rb +361 -0
- data/lib/bitcoin/validation.rb +369 -0
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin/wallet/coinselector.rb +3 -0
- data/lib/bitcoin/wallet/keygenerator.rb +3 -1
- data/lib/bitcoin/wallet/keystore.rb +6 -2
- data/lib/bitcoin/wallet/txdp.rb +6 -4
- data/lib/bitcoin/wallet/wallet.rb +54 -16
- data/spec/bitcoin/bitcoin_spec.rb +48 -3
- data/spec/bitcoin/builder_spec.rb +40 -17
- data/spec/bitcoin/fixtures/000000000000056b1a3d84a1e2b33cde8915a4b61c0cae14fca6d3e1490b4f98.json +3697 -0
- data/spec/bitcoin/fixtures/03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json +23 -0
- data/spec/bitcoin/fixtures/0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json +24 -0
- data/spec/bitcoin/fixtures/0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json +37 -0
- data/spec/bitcoin/fixtures/315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json +31 -0
- data/spec/bitcoin/fixtures/35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json +27 -0
- data/spec/bitcoin/fixtures/3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json +72 -0
- data/spec/bitcoin/fixtures/3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json +27 -0
- data/spec/bitcoin/fixtures/514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json +24 -0
- data/spec/bitcoin/fixtures/51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json +30 -0
- data/spec/bitcoin/fixtures/69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json +28 -0
- data/spec/bitcoin/fixtures/7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json +27 -0
- data/spec/bitcoin/fixtures/761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json +27 -0
- data/spec/bitcoin/fixtures/aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json +27 -0
- data/spec/bitcoin/fixtures/bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json +34 -0
- data/spec/bitcoin/fixtures/block-testnet-0000000000ac85bb2530a05a4214a387e6be02b22d3348abc5e7a5d9c4ce8dab.bin +0 -0
- data/spec/bitcoin/fixtures/cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json +24 -0
- data/spec/bitcoin/fixtures/ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json +41 -0
- data/spec/bitcoin/fixtures/f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json +23 -0
- data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.bin +0 -0
- data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.json +43 -0
- data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.bin +0 -0
- data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.json +67 -0
- data/spec/bitcoin/fixtures/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.bin +0 -0
- data/spec/bitcoin/fixtures/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.json +39 -0
- data/spec/bitcoin/fixtures/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.bin +0 -0
- data/spec/bitcoin/fixtures/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.json +39 -0
- data/spec/bitcoin/fixtures/rawblock-auxpow.bin +0 -0
- data/spec/bitcoin/fixtures/tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json +30 -0
- data/spec/bitcoin/fixtures/tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json +23 -0
- data/spec/bitcoin/fixtures/tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json +30 -0
- data/spec/bitcoin/fixtures/tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json +28 -0
- data/spec/bitcoin/key_spec.rb +128 -3
- data/spec/bitcoin/namecoin_spec.rb +182 -0
- data/spec/bitcoin/network_spec.rb +5 -3
- data/spec/bitcoin/node/command_api_spec.rb +376 -0
- data/spec/bitcoin/protocol/addr_spec.rb +2 -0
- data/spec/bitcoin/protocol/alert_spec.rb +2 -0
- data/spec/bitcoin/protocol/aux_pow_spec.rb +44 -0
- data/spec/bitcoin/protocol/block_spec.rb +134 -39
- data/spec/bitcoin/protocol/getblocks_spec.rb +32 -0
- data/spec/bitcoin/protocol/inv_spec.rb +10 -8
- data/spec/bitcoin/protocol/notfound_spec.rb +31 -0
- data/spec/bitcoin/protocol/ping_spec.rb +2 -0
- data/spec/bitcoin/protocol/tx_spec.rb +83 -17
- data/spec/bitcoin/protocol/version_spec.rb +7 -5
- data/spec/bitcoin/script/opcodes_spec.rb +412 -133
- data/spec/bitcoin/script/script_spec.rb +112 -13
- data/spec/bitcoin/spec_helper.rb +68 -0
- data/spec/bitcoin/storage/reorg_spec.rb +199 -0
- data/spec/bitcoin/storage/storage_spec.rb +337 -0
- data/spec/bitcoin/storage/validation_spec.rb +261 -0
- data/spec/bitcoin/wallet/coinselector_spec.rb +10 -7
- data/spec/bitcoin/wallet/keygenerator_spec.rb +2 -0
- data/spec/bitcoin/wallet/keystore_spec.rb +2 -0
- data/spec/bitcoin/wallet/txdp_spec.rb +2 -0
- data/spec/bitcoin/wallet/wallet_spec.rb +91 -58
- metadata +105 -51
- data/lib/bitcoin/storage/sequel.rb +0 -335
- data/spec/bitcoin/fixtures/0d0affb5964abe804ffe85e53f1dbb9f29e406aa3046e2db04fba240e63c7fdd.json +0 -27
- data/spec/bitcoin/fixtures/477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590.json +0 -27
- data/spec/bitcoin/reorg_spec.rb +0 -129
- data/spec/bitcoin/storage_spec.rb +0 -229
@@ -0,0 +1,182 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
require_relative 'spec_helper.rb'
|
4
|
+
require 'bitcoin/script'
|
5
|
+
|
6
|
+
include Bitcoin
|
7
|
+
include Bitcoin::Builder
|
8
|
+
|
9
|
+
describe 'Bitcoin::Namecoin' do
|
10
|
+
|
11
|
+
describe :script do
|
12
|
+
|
13
|
+
before do
|
14
|
+
Bitcoin.network = :namecoin
|
15
|
+
@name_new = Script.from_string("3045022023686b3584247c07f483de4048f3d5136c4faa2f961a6d1e487eb77437422b51022100b1ea62910f2dbb0533d32bd661e8a212d129057d3d71620572278895dbb5c7b501
|
16
|
+
04b656d7be83e73344e298feba41b38c52ea50d4583ead0c947fd8019f75c906e0d810c5d167ee616c46d28d7cb5ca1d7a20a180470c9dad79524118bafe6cf569 1 820fa9c6d252d6773e4ef26a2feffa93f0237641 OP_2DROP OP_DUP OP_HASH160 eb86f8f23909e248d199192d8407881c3435a5db OP_EQUALVERIFY OP_CHECKSIG")
|
17
|
+
@name_firstupdate = Script.from_string("3044022054e1557304c504498f8d40b961373d7401a4e4c1650518db8a9c3a49ee9add7e022061573b2837598c346b21c01969081a309c055d5da23b0ac7e139a6290f2f0a4b01
|
18
|
+
04d2628245cdfc6ccf5a762d303ba8a10bd54d597cfdcbf0ac3823bae666a36bb744ed44a2384f42525e37b5b1150c5321718806c0f941904336588dd624f4ce93 2 642f626974636f696e a8c22832fb0d40e900 7b22696e666f223a7b22726567697374726172223a22687474703a2f2f72656769737465722e646f742d6269742e6f7267227d2c22656d61696c223a2022726567697374657240646f742d6269742e6f7267222c226e73223a5b226e73302e7765622d73776565742d7765622e6e6574222c226e73312e7765622d73776565742d7765622e6e6574225d2c226d6170223a7b22223a7b226e73223a5b226e73302e7765622d73776565742d7765622e6e6574222c226e73312e7765622d73776565742d7765622e6e6574225d7d7d7d OP_2DROP OP_2DROP OP_DUP OP_HASH160 f3f4aee9d80da759a4a3547cf6aa95c09881decb OP_EQUALVERIFY OP_CHECKSIG")
|
19
|
+
@name_update = Script.from_string("304402206a8598a87aadd697732d0a187220023e2b54e542e144d0dee67660c8ca3d66f4022000de36f02afb9162f2d27e947d452d4e28baadfdb21637db2b1f252ad62d7fb201
|
20
|
+
04b61d1529dbe912c84d0de898e88ab8a9d9fa4a13e76e7b60419dd3bd2b72021842bbf0f5eba1001d55f0c6f2c255289bedbe843d0164b545bbc056f150b4c3f2 3 642f626974636f696e 7b22696e666f223a7b22726567697374726172223a22687474703a2f2f72656769737465722e646f742d6269742e6f7267227d2c22656d61696c223a2022726567697374657240646f742d6269742e6f7267222c226e73223a5b226e73302e7765622d73776565742d7765622e6e6574222c226e73312e7765622d73776565742d7765622e6e6574225d2c226d6170223a7b22223a7b226e73223a5b226e73302e7765622d73776565742d7765622e6e6574222c226e73312e7765622d73776565742d7765622e6e6574225d7d7d7d OP_2DROP OP_DROP OP_DUP OP_HASH160 8f29c40b89ceda0b9176819e2bb5a15f592c6548 OP_EQUALVERIFY OP_CHECKSIG")
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should parse name_new script' do
|
24
|
+
@name_new.is_name_new?.should == true
|
25
|
+
@name_firstupdate.is_name_new?.should == false
|
26
|
+
@name_update.is_name_new?.should == false
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should parse name_firstupdate script' do
|
30
|
+
@name_new.is_name_firstupdate?.should == false
|
31
|
+
@name_firstupdate.is_name_firstupdate?.should == true
|
32
|
+
@name_update.is_name_firstupdate?.should == false
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should parse name_update script' do
|
36
|
+
@name_new.is_name_update?.should == false
|
37
|
+
@name_firstupdate.is_name_update?.should == false
|
38
|
+
@name_update.is_name_update?.should == true
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should run scripts' do
|
42
|
+
@name_new.run { true }.should == true
|
43
|
+
@name_firstupdate.run { true }.should == true
|
44
|
+
@name_update.run { true }.should == true
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should get name_hash' do
|
48
|
+
@name_new.get_namecoin_hash.should == "820fa9c6d252d6773e4ef26a2feffa93f0237641"
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should get name' do
|
52
|
+
@name_firstupdate.get_namecoin_name.should == "d/bitcoin"
|
53
|
+
@name_update.get_namecoin_name.should == "d/bitcoin"
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should get value' do
|
57
|
+
@name_firstupdate.get_namecoin_value.should == '{"info":{"registrar":"http://register.dot-bit.org"},"email": "register@dot-bit.org","ns":["ns0.web-sweet-web.net","ns1.web-sweet-web.net"],"map":{"":{"ns":["ns0.web-sweet-web.net","ns1.web-sweet-web.net"]}}}'
|
58
|
+
@name_update.get_namecoin_value.should == @name_firstupdate.get_namecoin_value
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_rand rand; @rand = rand; end
|
62
|
+
|
63
|
+
it 'should create scripts' do
|
64
|
+
key = Key.generate
|
65
|
+
script = Script.to_name_new_script(self, "test/foo", key.addr)
|
66
|
+
Script.new(script).to_string.should =~
|
67
|
+
/^1 (.*?) OP_2DROP OP_DUP OP_HASH160 #{key.hash160} OP_EQUALVERIFY OP_CHECKSIG$/
|
68
|
+
@rand.should != nil
|
69
|
+
|
70
|
+
script = Script.to_name_firstupdate_script("test/foo", "1234", "testing", key.addr)
|
71
|
+
Script.new(script).to_string.should ==
|
72
|
+
"2 746573742f666f6f 1234 74657374696e67 OP_2DROP OP_2DROP " +
|
73
|
+
"OP_DUP OP_HASH160 #{key.hash160} OP_EQUALVERIFY OP_CHECKSIG"
|
74
|
+
|
75
|
+
script = Script.to_name_update_script("test/foo", "more testing", key.addr)
|
76
|
+
Script.new(script).to_string.should ==
|
77
|
+
"3 746573742f666f6f 6d6f72652074657374696e67 OP_2DROP OP_DROP " +
|
78
|
+
"OP_DUP OP_HASH160 #{key.hash160} OP_EQUALVERIFY OP_CHECKSIG"
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
[
|
84
|
+
{ :name => :utxo, :db => 'sqlite:/', utxo_cache: 0 },
|
85
|
+
{ :name => :sequel, :db => 'sqlite:/' },
|
86
|
+
].each do |configuration|
|
87
|
+
|
88
|
+
describe "Namecoin (#{configuration[:name]} store)" do
|
89
|
+
|
90
|
+
before do
|
91
|
+
Bitcoin.network = :namecoin
|
92
|
+
class Bitcoin::Validation::Block; def difficulty; true; end; end
|
93
|
+
class Bitcoin::Validation::Block; def min_timestamp; true; end; end
|
94
|
+
Bitcoin.network[:proof_of_work_limit] = Bitcoin.encode_compact_bits("ff"*32)
|
95
|
+
[:name_new, :name_firstupdate, :name_update].each {|type|
|
96
|
+
Bitcoin::Storage::Backends::SequelStore::SCRIPT_TYPES << type }
|
97
|
+
@store = Bitcoin::Storage.send(configuration[:name], configuration)
|
98
|
+
@store.reset
|
99
|
+
@store.log.level = :error
|
100
|
+
@key = Bitcoin::Key.generate
|
101
|
+
@block = create_block "00"*32, false, [], @key
|
102
|
+
Bitcoin.network[:genesis_hash] = @block.hash
|
103
|
+
@store.store_block(@block)
|
104
|
+
end
|
105
|
+
|
106
|
+
def set_rand r; @rand = r; end
|
107
|
+
|
108
|
+
it "should store names" do
|
109
|
+
# create name_new
|
110
|
+
@block = create_block @block.hash, true, [->(t) {
|
111
|
+
t.input {|i| i.prev_out @block.tx[0]; i.prev_out_index 0; i.signature_key @key }
|
112
|
+
t.output {|o| o.value 50e8; o.script {|s| s.type(:name_new)
|
113
|
+
s.recipient(self, "test", @key.addr) } } }], @key
|
114
|
+
@store.db[:names][hash: Bitcoin.hash160(@rand + "test".hth)].should != nil
|
115
|
+
|
116
|
+
# name_firstupdate should not be valid yet
|
117
|
+
@block = create_block @block.hash, true, [->(t) {
|
118
|
+
t.input {|i| i.prev_out @block.tx[0]; i.prev_out_index 0; i.signature_key @key }
|
119
|
+
t.output {|o| o.value 50e8; o.script {|s| s.type(:name_firstupdate)
|
120
|
+
s.recipient("test", @rand, "testvalue", @key.addr) } } }], @key
|
121
|
+
@store.name_show("test").should == nil
|
122
|
+
|
123
|
+
# create enough blocks for name_new to become valid
|
124
|
+
Namecoin::FIRSTUPDATE_LIMIT.times {
|
125
|
+
@block = create_block @block.hash, true, [], @key }
|
126
|
+
|
127
|
+
# name_firstupdate should be valid now
|
128
|
+
@block = create_block @block.hash, true, [->(t) {
|
129
|
+
t.input {|i| i.prev_out @block.tx[0]; i.prev_out_index 0; i.signature_key @key }
|
130
|
+
t.output {|o| o.value 50e8; o.script {|s|; s.type(:name_firstupdate)
|
131
|
+
s.recipient("test", @rand, "testvalue", @key.addr) } } }], @key
|
132
|
+
|
133
|
+
name = @store.name_show("test")
|
134
|
+
name.get_address.should == @key.addr
|
135
|
+
name.name.should == "test"
|
136
|
+
name.value.should == "testvalue"
|
137
|
+
name.hash.should == Bitcoin.hash160(@rand + "test".hth)
|
138
|
+
|
139
|
+
# create name_update
|
140
|
+
@new_key = Bitcoin::Key.generate
|
141
|
+
@block = create_block @block.hash, true, [->(t) {
|
142
|
+
t.input {|i| i.prev_out @block.tx[0]; i.prev_out_index 0; i.signature_key @key}
|
143
|
+
t.output {|o|o.value 50e8; o.script {|s| s.type(:name_update)
|
144
|
+
s.recipient("test", "testupdate", @new_key.addr) } } }], @new_key
|
145
|
+
|
146
|
+
name = @store.name_show("test")
|
147
|
+
name.get_address.should == @new_key.addr
|
148
|
+
name.value.should == "testupdate"
|
149
|
+
|
150
|
+
h = @store.name_history("test")
|
151
|
+
h.size.should == 2
|
152
|
+
h[0].value.should == "testvalue"
|
153
|
+
h[0].get_address.should == @key.addr
|
154
|
+
h[1].value.should == "testupdate"
|
155
|
+
h[1].get_address.should == @new_key.addr
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should expire names" do
|
159
|
+
@block = create_block @block.hash, true, [->(t) {
|
160
|
+
t.input {|i| i.prev_out @block.tx[0]; i.prev_out_index 0; i.signature_key @key }
|
161
|
+
t.output {|o| o.value 50e8; o.script {|s| s.type(:name_new)
|
162
|
+
s.recipient(self, "test", @key.addr) } } }], @key
|
163
|
+
@store.db[:names][hash: Bitcoin.hash160(@rand + "test".hth)].should != nil
|
164
|
+
|
165
|
+
# create enough blocks for name_new to become valid
|
166
|
+
Namecoin::FIRSTUPDATE_LIMIT.times {
|
167
|
+
@block = create_block @block.hash, true, [], @key }
|
168
|
+
|
169
|
+
# name_firstupdate should be valid now
|
170
|
+
@block = create_block @block.hash, true, [->(t) {
|
171
|
+
t.input {|i| i.prev_out @block.tx[0]; i.prev_out_index 0; i.signature_key @key }
|
172
|
+
t.output {|o| o.value 50e8; o.script {|s|; s.type(:name_firstupdate)
|
173
|
+
s.recipient("test", @rand, "testvalue", @key.addr) } } }], @key
|
174
|
+
|
175
|
+
@store.name_show("test").expires_in.should == Namecoin::EXPIRATION_DEPTH
|
176
|
+
@block = create_block @block.hash, true, [], @key
|
177
|
+
@store.name_show("test").expires_in.should == Namecoin::EXPIRATION_DEPTH - 1
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
1
3
|
require_relative 'spec_helper.rb'
|
2
4
|
|
3
5
|
describe 'Bitcoin::network' do
|
@@ -9,19 +11,19 @@ describe 'Bitcoin::network' do
|
|
9
11
|
net[:address_version].should == "00"
|
10
12
|
net[:genesis_hash].should == "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
|
11
13
|
end
|
12
|
-
|
14
|
+
|
13
15
|
it 'can be set to main net' do
|
14
16
|
Bitcoin::network = :bitcoin
|
15
17
|
Bitcoin::network.should == Bitcoin::NETWORKS[:bitcoin]
|
16
18
|
end
|
17
|
-
|
19
|
+
|
18
20
|
class Test_Handler
|
19
21
|
attr_reader :inv
|
20
22
|
def on_inv_transaction inv
|
21
23
|
@inv = inv
|
22
24
|
end
|
23
25
|
end
|
24
|
-
|
26
|
+
|
25
27
|
it 'uses correct magic_head when parsing a message' do
|
26
28
|
pkt = ["f9 be b4 d9 69 6e 76 00 00 00 00 00 00 00 00 00 49 00 00 00 11 ea 1c 91 02 01 00 00 00 e0 41 c2 38 f7 32 1a 68 0a 34 06 bf fd 72 12 e3 d1 2c b5 12 2a 8c 0b 52 76 de 82 30 b1 00 7a 42 01 00 00 00 33 00 09 71 a9 70 7b 6c 6d 6e 77 aa 2e ac 43 f3 e5 67 84 cb 61 b2 35 fb 8d fe e0 86 8b 40 7c f3".split(" ").join].pack("H*")
|
27
29
|
|
@@ -0,0 +1,376 @@
|
|
1
|
+
require_relative '../spec_helper.rb'
|
2
|
+
|
3
|
+
include Bitcoin
|
4
|
+
include Builder
|
5
|
+
|
6
|
+
describe 'Node Command API' do
|
7
|
+
|
8
|
+
def test_command command, params = [], response = nil, &block
|
9
|
+
$responses = {}
|
10
|
+
EM.run do
|
11
|
+
@client = Bitcoin::Network::CommandClient.connect(*@config[:command]) do
|
12
|
+
on_connected do
|
13
|
+
request(command, *params)
|
14
|
+
end
|
15
|
+
on_response do |cmd, data|
|
16
|
+
$responses[cmd] = data
|
17
|
+
EM.stop
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
result = $responses[command]
|
23
|
+
|
24
|
+
return result unless response || block
|
25
|
+
|
26
|
+
if block
|
27
|
+
block.call(result)
|
28
|
+
else
|
29
|
+
result.should == response
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
before do
|
35
|
+
Bitcoin::Validation::Block::RULES.merge({
|
36
|
+
syntax: [:hash, :tx_list, :bits, :max_timestamp, :coinbase, :coinbase_scriptsig, :transactions_syntax],
|
37
|
+
context: [:prev_hash, :coinbase_value, :min_timestamp, :transactions_context]
|
38
|
+
})
|
39
|
+
|
40
|
+
Bitcoin.network = :spec
|
41
|
+
@config = {
|
42
|
+
listen: ["127.0.0.1", 38333],
|
43
|
+
command: ["127.0.0.1", 38332],
|
44
|
+
storage: "sequel::sqlite:/",
|
45
|
+
dns: false,
|
46
|
+
intervals: { queue: 0.01 },
|
47
|
+
log: { network: :warn, storage: :warn },
|
48
|
+
}
|
49
|
+
|
50
|
+
@node = Bitcoin::Network::Node.new(@config)
|
51
|
+
@pid = fork do
|
52
|
+
$stdout = StringIO.new
|
53
|
+
SimpleCov.running = false if defined?(SimpleCov)
|
54
|
+
@node.run
|
55
|
+
end
|
56
|
+
|
57
|
+
@genesis = P::Block.new("0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000".htb)
|
58
|
+
|
59
|
+
Bitcoin.network[:proof_of_work_limit] = Bitcoin.encode_compact_bits("ff"*32)
|
60
|
+
@key = Bitcoin::Key.generate
|
61
|
+
@block = create_block @genesis.hash, false, [], @key
|
62
|
+
|
63
|
+
test_command "store_block", [@genesis.to_payload.hth]
|
64
|
+
sleep 0.1
|
65
|
+
end
|
66
|
+
|
67
|
+
after do
|
68
|
+
Process.kill("TERM", @pid)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should return error for unknown command" do
|
72
|
+
test_command("foo").should == {"error" => "unknown command: foo. send 'help' for help."}
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should return error for wrong parameters" do
|
76
|
+
test_command("info", "foo").should == {"error" => "wrong number of arguments (1 for 0)"}
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should query tslb" do
|
80
|
+
test_command("tslb") do |res|
|
81
|
+
res.keys.include?("tslb").should == true
|
82
|
+
res["tslb"].should >= 0
|
83
|
+
res["tslb"].should <= 1
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should query info" do
|
88
|
+
info = test_command "info"
|
89
|
+
info.is_a?(Hash).should == true
|
90
|
+
info["blocks"].should == "0 (?)"
|
91
|
+
info["addrs"].should == "0 (0)"
|
92
|
+
info["connections"].should == "0 established (0 out, 0 in), 0 connecting"
|
93
|
+
info["queue"].should == 0
|
94
|
+
info["inv_queue"].should == 0
|
95
|
+
info["inv_cache"].should == 0
|
96
|
+
info["network"].should == "bitcoin"
|
97
|
+
info["storage"].should == "sequel::sqlite:/"
|
98
|
+
info["version"].should == 70001
|
99
|
+
info["external_ip"].should == "127.0.0.1"
|
100
|
+
info["uptime"].should =~ /00:00:00:0[0|1]/
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should query config" do
|
104
|
+
test_command("config").should == JSON.load(@node.config.to_json)
|
105
|
+
end
|
106
|
+
|
107
|
+
# TODO
|
108
|
+
it "should query connections" do
|
109
|
+
test_command("connections").should == []
|
110
|
+
end
|
111
|
+
|
112
|
+
# TODO
|
113
|
+
it "should connect" do
|
114
|
+
test_command("connect", ["127.0.0.1:1234"])["state"].should == "Connecting..."
|
115
|
+
end
|
116
|
+
|
117
|
+
# TODO
|
118
|
+
it "should disconnect" do
|
119
|
+
test_command("disconnect", ["127.0.0.1:1234"])["state"].should == "Disconnected"
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should store block" do
|
123
|
+
test_command("info")["blocks"].should == "0 (?)"
|
124
|
+
res = test_command "store_block", [ @block.to_payload.hth ]
|
125
|
+
res.should == { "queued" => [ "block", @block.hash ] }
|
126
|
+
sleep 0.1
|
127
|
+
test_command("info")["blocks"].should == "1 (?) sync"
|
128
|
+
end
|
129
|
+
|
130
|
+
describe :create_tx do
|
131
|
+
|
132
|
+
before do
|
133
|
+
@key2 = Key.generate
|
134
|
+
test_command("store_block", [@block.to_payload.hth])
|
135
|
+
sleep 0.1
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should create transaction from given private keys" do
|
139
|
+
res = test_command("create_tx", [[@key.to_base58], [[@key2.addr, 10e8], [@key.addr, 40e8]]])
|
140
|
+
tx = P::Tx.new(res[0].htb)
|
141
|
+
tx.is_a?(P::Tx).should == true
|
142
|
+
tx.verify_input_signature(0, @block.tx[0]).should == true
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should create transaction from given addresses" do
|
146
|
+
res = test_command("create_tx", [[@key.addr], [[@key2.addr, 10e8], [@key.addr, 40e8]]])
|
147
|
+
tx = P::Tx.new(res[0].htb)
|
148
|
+
tx.is_a?(P::Tx).should == true
|
149
|
+
tx.in[0].script_sig.should == ""
|
150
|
+
-> { tx.verify_input_signature(0, @block.tx[0]) }.should.raise(TypeError)
|
151
|
+
|
152
|
+
res[1].each.with_index do |sig_data, idx|
|
153
|
+
sig_hash, sig_addr = *sig_data
|
154
|
+
sig_addr.should == @key.addr
|
155
|
+
sig = @key.sign(sig_hash.htb)
|
156
|
+
script_sig = Script.to_signature_pubkey_script(sig, @key.pub.htb)
|
157
|
+
tx.in[idx].script_sig_length = script_sig.bytesize
|
158
|
+
tx.in[idx].script_sig = script_sig
|
159
|
+
end
|
160
|
+
|
161
|
+
tx.verify_input_signature(0, @block.tx[0]).should == true
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should create transaction from given pubkeys" do
|
165
|
+
res = test_command("create_tx", [[@key.pub], [[@key2.addr, 10e8], [@key.addr, 40e8]]])
|
166
|
+
tx = P::Tx.new(res[0].htb)
|
167
|
+
tx.is_a?(P::Tx).should == true
|
168
|
+
-> { tx.verify_input_signature(0, @block.tx[0]) }.should.raise(TypeError)
|
169
|
+
|
170
|
+
res[1].each.with_index do |sig_data, idx|
|
171
|
+
sig_hash, sig_addr = *sig_data
|
172
|
+
sig_addr.should == @key.addr
|
173
|
+
sig = @key.sign(sig_hash.htb)
|
174
|
+
script_sig = Script.to_signature_pubkey_script(sig, @key.pub.htb)
|
175
|
+
tx.in[idx].script_sig_length = script_sig.bytesize
|
176
|
+
tx.in[idx].script_sig = script_sig
|
177
|
+
end
|
178
|
+
|
179
|
+
tx.verify_input_signature(0, @block.tx[0]).should == true
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
describe :assemble_tx do
|
185
|
+
|
186
|
+
it "should assemble tx from unsigned tx structure, signatures and pubkeys" do
|
187
|
+
tx = build_tx do |t|
|
188
|
+
t.input do |i|
|
189
|
+
i.prev_out @block.tx[0]
|
190
|
+
i.prev_out_index 0
|
191
|
+
end
|
192
|
+
t.output {|o| o.value 50e8; o.script {|s| s.recipient @key.addr } }
|
193
|
+
end
|
194
|
+
sig = @key.sign(tx.in[0].sig_hash)
|
195
|
+
test_command("store_block", [@block.to_payload.hth])
|
196
|
+
sleep 0.1
|
197
|
+
res = test_command("assemble_tx", [tx.to_payload.hth, [[sig.hth, @key.pub]]])
|
198
|
+
tx = Bitcoin::P::Tx.new(res.htb)
|
199
|
+
tx.verify_input_signature(0, @block.tx[0]).should == true
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
describe :relay_tx do
|
205
|
+
|
206
|
+
it "should handle decoding error" do
|
207
|
+
res = test_command("relay_tx", ["foobar"])
|
208
|
+
res["error"].should == "Error decoding transaction."
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should handle syntax error" do
|
212
|
+
# create transaction with invalid output size
|
213
|
+
block = create_block(@block.hash, false, [->(t) {
|
214
|
+
create_tx(t, @block.tx[0], 0, [[22e14, @key]]) }], @key)
|
215
|
+
tx = block.tx[1]
|
216
|
+
|
217
|
+
error = test_command("relay_tx", [tx.to_payload.hth])
|
218
|
+
error["error"].should == "Transaction syntax invalid."
|
219
|
+
error["details"].should == ["output_values", [22e14, 21e14]]
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should handle context error" do
|
223
|
+
# create transaction with invalid input
|
224
|
+
block = create_block(@block.hash, false, [->(t) {
|
225
|
+
create_tx(t, @block.tx[0], 0, [[25e8, @key]]) }], @key)
|
226
|
+
tx = block.tx[1]
|
227
|
+
|
228
|
+
error = test_command("relay_tx", [tx.to_payload.hth])
|
229
|
+
error["error"].should == "Transaction context invalid."
|
230
|
+
error["details"].should == ["prev_out", [[@block.tx[0].hash, 0]]]
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should relay transaction" do
|
234
|
+
block = create_block(@block.hash, false, [->(t) {
|
235
|
+
create_tx(t, @block.tx[0], 0, [[25e8, @key]]) }], @key)
|
236
|
+
tx = block.tx[1]
|
237
|
+
|
238
|
+
test_command("store_block", [@block.to_payload.hth])
|
239
|
+
sleep 0.1
|
240
|
+
res = test_command("relay_tx", [tx.to_payload.hth, 1, 0])
|
241
|
+
res["success"].should == true
|
242
|
+
res["hash"].should == tx.hash
|
243
|
+
res["propagation"].should == { "sent" => 1, "received" => 0, "percent" => 0.0 }
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
describe :monitor do
|
249
|
+
|
250
|
+
before do
|
251
|
+
@client = TCPSocket.new(*@config[:command])
|
252
|
+
|
253
|
+
def send data
|
254
|
+
@client.write(data.to_json + "\x00")
|
255
|
+
end
|
256
|
+
|
257
|
+
def should_receive expected
|
258
|
+
buf = ""
|
259
|
+
while b = @client.read(1)
|
260
|
+
break if b == "\x00"
|
261
|
+
buf << b
|
262
|
+
end
|
263
|
+
resp = JSON.load(buf)
|
264
|
+
resp.should == expected
|
265
|
+
end
|
266
|
+
|
267
|
+
def store_block block
|
268
|
+
send ["store_block", [ block.to_payload.hth ]]
|
269
|
+
should_receive ["store_block", {"queued" => [ "block", block.hash ]}]
|
270
|
+
end
|
271
|
+
|
272
|
+
end
|
273
|
+
|
274
|
+
describe :block do
|
275
|
+
|
276
|
+
before do
|
277
|
+
send ["monitor", ["block"]]
|
278
|
+
should_receive ["monitor", ["block", [ @genesis.to_hash, 0 ]]]
|
279
|
+
store_block @block
|
280
|
+
should_receive ["monitor", ["block", [ @block.to_hash, 1 ]]]
|
281
|
+
end
|
282
|
+
|
283
|
+
it "should monitor block" do
|
284
|
+
@block = create_block @block.hash, false
|
285
|
+
store_block @block
|
286
|
+
should_receive ["monitor", ["block", [ @block.to_hash, 2 ]]]
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
it "should not monitor side or orphan blocks" do
|
291
|
+
@side = create_block @genesis.hash, false
|
292
|
+
store_block @side
|
293
|
+
|
294
|
+
@orphan = create_block "00" * 32, false
|
295
|
+
store_block @orphan
|
296
|
+
|
297
|
+
# should not send side or orphan block only the next main block
|
298
|
+
@block = create_block @block.hash, false
|
299
|
+
store_block @block
|
300
|
+
should_receive ["monitor", ["block", [ @block.to_hash, 2 ]]]
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
|
305
|
+
describe :tx do
|
306
|
+
|
307
|
+
it "should monitor unconfirmed tx" do
|
308
|
+
send ["monitor", ["tx"]]
|
309
|
+
tx = @block.tx[0]
|
310
|
+
send ["store_tx", [ tx.to_payload.hth ] ]
|
311
|
+
should_receive ["store_tx", { "queued" => [ "tx", tx.hash ]}]
|
312
|
+
should_receive ["monitor", ["tx", [ tx.to_hash, 0 ]]]
|
313
|
+
end
|
314
|
+
|
315
|
+
it "should monitor confirmed tx" do
|
316
|
+
send ["monitor", ["tx_1"]]
|
317
|
+
store_block @block
|
318
|
+
should_receive ["monitor", ["tx_1", [ @block.tx[0].to_hash, 1 ]]]
|
319
|
+
end
|
320
|
+
|
321
|
+
it "should monitor tx for given confirmation level" do
|
322
|
+
send ["monitor", ["tx_3"]]
|
323
|
+
@tx = @block.tx[0]
|
324
|
+
store_block @block
|
325
|
+
@block = create_block @block.hash, false
|
326
|
+
store_block @block
|
327
|
+
should_receive ["monitor", ["tx_3", [ @genesis.tx[0].to_hash, 3 ]]]
|
328
|
+
@block = create_block @block.hash, false
|
329
|
+
store_block @block
|
330
|
+
should_receive ["monitor", ["tx_3", [ @tx.to_hash, 3 ]]]
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
describe :output do
|
336
|
+
|
337
|
+
before do
|
338
|
+
@tx = @block.tx[0]; @out = @tx.out[0]
|
339
|
+
@addr = Bitcoin::Script.new(@out.pk_script).get_address
|
340
|
+
end
|
341
|
+
|
342
|
+
it "should monitor unconfirmed outputs" do
|
343
|
+
send ["monitor", ["output"]]
|
344
|
+
tx = @block.tx[0]
|
345
|
+
send ["store_tx", [ tx.to_payload.hth ]]
|
346
|
+
should_receive ["store_tx", { "queued" => [ "tx", tx.hash ]}]
|
347
|
+
addr = Bitcoin::Script.new(tx.out[0].pk_script).get_address
|
348
|
+
should_receive ["monitor", ["output", [ tx.hash, addr, tx.out[0].value, 0]]]
|
349
|
+
end
|
350
|
+
|
351
|
+
it "should monitor confirmed output" do
|
352
|
+
send ["monitor", ["output_1"]]
|
353
|
+
store_block @block
|
354
|
+
should_receive ["monitor", ["output_1", [ @tx.hash, @addr, @out.value, 1 ]]]
|
355
|
+
end
|
356
|
+
|
357
|
+
it "should monitor output for given confirmation level" do
|
358
|
+
send ["monitor", ["output_3"]]
|
359
|
+
store_block @block
|
360
|
+
@block = create_block @block.hash, false
|
361
|
+
store_block @block
|
362
|
+
tx = @genesis.tx[0]; out = tx.out[0]
|
363
|
+
addr = Bitcoin::Script.new(out.pk_script).get_address
|
364
|
+
should_receive ["monitor", ["output_3", [ tx.hash, addr, out.value, 3 ]]]
|
365
|
+
|
366
|
+
@block = create_block @block.hash, false
|
367
|
+
store_block @block
|
368
|
+
should_receive ["monitor", ["output_3", [ @tx.hash, @addr, @out.value, 3 ]]]
|
369
|
+
|
370
|
+
end
|
371
|
+
|
372
|
+
end
|
373
|
+
|
374
|
+
end
|
375
|
+
|
376
|
+
end
|