blockchain-ruby 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 741747d1cc360130278facebe80df167706167a2
4
+ data.tar.gz: 6eed1fa2d389cd2e2ddd1d983a2db76dc9bc543d
5
+ SHA512:
6
+ metadata.gz: a9d07d23a07df7a27941b5242784045ad6045da4fff26d286521173f5b92c843a38ee584140eed0c5c4f9f684750a797c983897709309882c3f20eebb4bcbd4d
7
+ data.tar.gz: 414e3b362df7b07dd800de6168f4e397a5e52dedf85de88b30a92bd09d358f905b2ea279b04a4de01e9cc5d3685c860b86046a8254f432a52b248c3991930ff2
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .idea
2
+ .DS_STORE
3
+
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec #specifying gem dependencies in blockchain-ruby.gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,41 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ blockchain-ruby (1.0.0)
5
+ bitcoin-money (~> 0.5.1)
6
+ monetize (~> 0.3.0)
7
+ money (~> 6.1.1)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ bitcoin-money (0.5.1)
13
+ diff-lcs (1.2.5)
14
+ fakeweb (1.3.0)
15
+ i18n (0.6.11)
16
+ monetize (0.3.0)
17
+ money (~> 6.1.0.beta1)
18
+ money (6.1.1)
19
+ i18n (~> 0.6.4)
20
+ rake (10.3.2)
21
+ rspec (3.0.0)
22
+ rspec-core (~> 3.0.0)
23
+ rspec-expectations (~> 3.0.0)
24
+ rspec-mocks (~> 3.0.0)
25
+ rspec-core (3.0.1)
26
+ rspec-support (~> 3.0.0)
27
+ rspec-expectations (3.0.1)
28
+ diff-lcs (>= 1.2.0, < 2.0)
29
+ rspec-support (~> 3.0.0)
30
+ rspec-mocks (3.0.1)
31
+ rspec-support (~> 3.0.0)
32
+ rspec-support (3.0.0)
33
+
34
+ PLATFORMS
35
+ ruby
36
+
37
+ DEPENDENCIES
38
+ blockchain-ruby!
39
+ fakeweb (~> 1.3.0)
40
+ rake
41
+ rspec (~> 3.0.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,96 @@
1
+ blockchain-ruby
2
+ ===============
3
+
4
+ Gives Rubyists the ability to traverse the blockchain in a semantic way.
5
+
6
+ The following functionality has been implemented:
7
+
8
+ Addresses
9
+ ---------
10
+ Search for addresses with hash160 or address
11
+
12
+ returns `nil` if not found
13
+ ~~~ruby
14
+ a = Blockchain::Address.find('143y8gQbhmgePi4QJyL6QBi8zk4PSM5KQr')
15
+ a.hash160 # => '217810f57fd7cdf79274c5d5e4a891fadc74887b'
16
+ a.address # => '143y8gQbhmgePi4QJyL6QBi8zk4PSM5KQr'
17
+ a.n_tx # => 143
18
+ a.n_unredeemed # => 56
19
+ a.total_received # => #<Btc BTC:0.00124124 mBTC:1.24124 uBTC:1241.24 Satoshis:124124.0>
20
+ a.total_sent # => #<Btc BTC:5.829e-05 mBTC:0.05829 uBTC:58.29 Satoshis:5829.0>
21
+ a.final_balance # => #<Btc BTC:0.00090215 mBTC:0.90215 uBTC:902.15 Satoshis:90215.0>
22
+ a.refresh! # refreshes the address
23
+ a.to_s # => '217810f57fd7cdf79274c5d5e4a891fadc74887b'
24
+ a.first_seen # => #<DateTime: 2014-08-22T18:05:32-04:00 ((2456892j,79532s,800786000n),-14400s,2299161j)>
25
+ txs = a.txs
26
+ ~~~
27
+
28
+ Transactions
29
+ ------------
30
+ Search for transactions with transaction index or hash
31
+
32
+ returns `nil` if not found
33
+ ~~~ruby
34
+ t = txs[0]
35
+ t.hsh # => 'bebc1f8db50669d8ab7c7181aa92ffe3f170510d5894cb0a4100af23e335210f'
36
+ t.ver # => 1
37
+ t.vin_sz # => 1
38
+ t.vout_sz # => 2
39
+ t.time # => #<DateTime: 2014-08-22T18:05:32-04:00 ((2456892j,79532s,800786000n),-14400s,2299161j)>
40
+ t.size # => 258
41
+ t.result # => 0
42
+ t.relayed_by # => "127.0.01"
43
+ t.double_spend # => false
44
+ t.block_height # => 317010
45
+ t.tx_index # => 62922222
46
+
47
+ t.txtotalbtcoutput # => #<Btc BTC:0.00124124 mBTC:1.24124 uBTC:1241.24 Satoshis:124124.0>
48
+ t.txtotalbtcinput # => #<Btc BTC:5.829e-05 mBTC:0.05829 uBTC:58.29 Satoshis:5829.0>
49
+ t.txfee # => #<Btc BTC:0.00090215 mBTC:0.90215 uBTC:902.15 Satoshis:90215.0>
50
+
51
+ inputs = t.inputs # array of Blockchain::Transaction::Input
52
+ out = t.out # array of Blockchain::Transaction::Output
53
+
54
+ # INPUTs
55
+ i = inputs[0]
56
+ i.script # => '76a9141f689f046aae32021905eeec37baef94dd591ff588ac'
57
+ i.prev_out # => Blockchain::Transaction.find(62918382) | the tx_index of last tx
58
+
59
+ # OUTPUTs
60
+ o = out[0]
61
+ o.script # => '76a9141f689f046aae32021905eeec37baef94dd591ff588ac'
62
+ o.n # => 0
63
+ o.value # => 10000
64
+ o.addr # => '13s5H9qsCDxsbCuZF5mGbg6rMLziQAnrxr'
65
+ o.tx_index # => 62922222
66
+ o.spent # => true
67
+ o.type # => 0
68
+ ~~~
69
+
70
+ Blocks
71
+ ------
72
+ Search for blocks with block index or block hash
73
+
74
+ returns `nil` if not found
75
+ ~~~ruby
76
+ b = Blockchain::Block.find(458453)
77
+ b.hsh # => '000000000000000024b816f859d85a955dfe8db09e3735d51755cb5f9cf2f63f'
78
+ b.ver # => 2
79
+ b.prev_block # => '00000000000000000894f4f2cbd1dbc8dd0b6d2f3a9a89582f5456516f2bc7d9'
80
+ b.mrkl_root # => 'baab986e40ac0ea11b7fff8f207b9c8cdbcf49b6b58e66829f8fe9cc5c017e09'
81
+ b.time # => #<DateTime: 2014-08-22T22:12:23+00:00 ((2456892j,79943s,0n),+0s,2299161j)>
82
+ b.bits # => 405675096
83
+ b.fee # => #<Btc BTC:0.16328705 mBTC:163.28705 uBTC:163287.05 Satoshis:16328705.0>
84
+ b.nonce # => 2030590116
85
+ b.n_tx # => 979
86
+ b.size # => 539809
87
+ b.block_index # => 458453
88
+ b.main_chain # => true
89
+ b.height # => 317016
90
+ b.received_time # => #<DateTime: 2014-08-22T22:12:23+00:00 ((2456892j,79943s,0n),+0s,2299161j)>
91
+ b.relayed_by # => "193.187.79.76"
92
+ b.tx # => array of Blockchain::Transaction in the block
93
+ ~~~
94
+
95
+
96
+
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "blockchain-ruby"
7
+ gem.version = "1.0.0"
8
+ gem.authors = ["James Larisch"]
9
+ gem.email = ["root@jameslarisch.com"]
10
+ gem.description = "Convenient wrapper around public Blockchain.info API."
11
+ gem.summary = "Convenient wrapper around public Blockchain.info API."
12
+ gem.homepage = "https://github.com/zenchilabs/blockchain-ruby"
13
+
14
+ gem.files = `git ls-files`.split($/)
15
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
+ gem.require_paths = ["lib"]
18
+
19
+
20
+ gem.add_development_dependency "rspec", "~> 3.0.0"
21
+ gem.add_development_dependency "fakeweb", "~> 1.3.0"
22
+ gem.add_development_dependency "rake"
23
+
24
+ gem.add_dependency "money", "~> 6.1.1"
25
+ gem.add_dependency "monetize", "~> 0.3.0"
26
+ gem.add_dependency "bitcoin-money", "~> 0.5.1"
27
+ end
data/lib/address.rb ADDED
@@ -0,0 +1,48 @@
1
+ module Blockchain
2
+ class Address
3
+ attr_reader :hash160, :address, :total_received
4
+ attr_reader :total_sent, :final_balance, :txs
5
+
6
+ def self.find(address)
7
+ self.new(Blockchain.rawaddr(address)) rescue nil
8
+ end
9
+
10
+ def initialize(a)
11
+ meta_init(a)
12
+ end
13
+
14
+ private def meta_init(a)
15
+ a.each_key { |k| instance_variable_set("@#{k}", a[k]) }
16
+ @total_received = Btc.from_satoshis(@total_received || 0)
17
+ @total_sent = Btc.from_satoshis(@total_sent || 0)
18
+ @final_balance = Btc.from_satoshis(@final_balance || 0)
19
+ @txs.map! { |t| Blockchain::Transaction.new(t) }
20
+ end
21
+
22
+ def n_tx
23
+ @n_tx || 0
24
+ end
25
+
26
+ def n_unredeemed
27
+ @n_unredeemed || 0
28
+ end
29
+
30
+ def firstseen
31
+ DateTime.strptime(Blockchain.q("addressfirstseen/#{@address}"), '%s')
32
+ end
33
+
34
+ def to_s
35
+ @address
36
+ end
37
+
38
+ def ==(o)
39
+ o.instance_variables == self.instance_variables
40
+ end
41
+
42
+ def refresh!
43
+ address = @address
44
+ instance_variables.each { |i| instance_variable_set(i, nil) }
45
+ meta_init(Blockchain.rawaddr(address))
46
+ end
47
+ end
48
+ end
data/lib/block.rb ADDED
@@ -0,0 +1,27 @@
1
+ module Blockchain
2
+ class Block
3
+ attr_reader :hsh, :ver, :prev_block, :mrkl_root
4
+ attr_reader :time, :bits, :fee, :nonce, :n_tx, :size
5
+ attr_reader :block_index, :main_chain, :height, :received_time
6
+ attr_reader :relayed_by, :tx
7
+
8
+ # id can be block_hash or block_index
9
+ def self.find(id)
10
+ self.new(Blockchain.rawblock(id)) rescue nil
11
+ end
12
+
13
+ def initialize(b)
14
+ @hsh = b.delete('hash') # hash is an unfortunate word
15
+ b.each_key { |k| instance_variable_set("@#{k}", b[k]) }
16
+ @time = DateTime.strptime(@time.to_s, '%s')
17
+ @received_time = DateTime.strptime(@received_time.to_s, '%s')
18
+ @tx.map! { |t| Blockchain::Transaction.new(t) }
19
+ @fee = Btc.from_satoshis(fee)
20
+ end
21
+
22
+ def previous
23
+ Block.find(@prev_block)
24
+ end
25
+ end
26
+
27
+ end
data/lib/blockchain.rb ADDED
@@ -0,0 +1,35 @@
1
+ module Blockchain
2
+ ROOT = 'https://blockchain.info'
3
+
4
+ def self.get(path)
5
+ response = open("#{ROOT}/#{path}")
6
+ response.read if response.status.first == '200'
7
+ end
8
+
9
+ def self.q(path)
10
+ self.get("q/#{path}")
11
+ end
12
+
13
+ def self.rawblock(block)
14
+ JSON.parse(self.get("rawblock/#{block}"))
15
+ end
16
+
17
+ def self.rawtx(tx)
18
+ JSON.parse(self.get("rawtx/#{tx}"))
19
+ end
20
+
21
+ def self.rawaddr(address)
22
+ JSON.parse(self.get("rawaddr/#{address}"))
23
+ end
24
+ end
25
+
26
+ require 'money'
27
+ require 'bigdecimal'
28
+ require 'open-uri'
29
+ require 'date'
30
+ require 'btc'
31
+ require 'realtime'
32
+ require 'transaction'
33
+ require 'address'
34
+ require 'block'
35
+
data/lib/realtime.rb ADDED
@@ -0,0 +1,53 @@
1
+ module Blockchain
2
+ def self.difficulty
3
+ BigDecimal.new(self.q('getdifficulty'))
4
+ end
5
+
6
+ def self.block_count
7
+ self.q('getblockcount').to_i
8
+ end
9
+
10
+ def self.latest_hash
11
+ self.q('latesthash')
12
+ end
13
+
14
+ def self.bc_per_block
15
+ Btc.new(self.q('bcperblock'))
16
+ end
17
+
18
+ def self.total
19
+ Btc.new(self.q('totalbc'))
20
+ end
21
+
22
+ def self.probability
23
+ BigDecimal.new(self.q('probability'))
24
+ end
25
+
26
+ def self.hashes_to_win
27
+ self.q('hashestowin').to_i
28
+ end
29
+
30
+ def self.next_retarget
31
+ self.q('nextretarget').to_i
32
+ end
33
+
34
+ def self.avg_tx_size
35
+ self.q('avgtxsize').to_i
36
+ end
37
+
38
+ def self.avg_tx_value
39
+ self.q('avgtxvalue').to_i
40
+ end
41
+
42
+ def self.interval
43
+ BigDecimal.new(self.q('interval'))
44
+ end
45
+
46
+ def self.eta
47
+ BigDecimal.new(self.q('eta'))
48
+ end
49
+
50
+ def self.avg_tx_number
51
+ self.q('avgtxnumber').to_i
52
+ end
53
+ end
@@ -0,0 +1,59 @@
1
+ module Blockchain
2
+ class Transaction
3
+ attr_reader :hsh, :ver, :vin_sz, :vout_sz, :time, :size, :result, :double_spend
4
+ attr_reader :relayed_by, :block_height, :tx_index, :inputs, :out
5
+
6
+ def self.find(transaction)
7
+ self.new(Blockchain.rawtx(transaction))
8
+ end
9
+
10
+ def initialize(t)
11
+ @hsh = t.delete('hash')
12
+ t.each_key { |k| instance_variable_set("@#{k}", t[k]) }
13
+ @inputs.map! { |i| Input.new(i) }
14
+ @out.map! { |o| Output.new(o) }
15
+ @time = DateTime.strptime(@time.to_s, '%s')
16
+ end
17
+
18
+ def txtotalbtcoutput
19
+ Btc.from_satoshis(Blockchain.q("txtotalbtcoutput/#{@hsh}"))
20
+ end
21
+
22
+ def txtotalbtcinput
23
+ Btc.from_satoshis(Blockchain.q("txtotalbtcinput/#{@hsh}"))
24
+ end
25
+
26
+ def txfee
27
+ Btc.from_satoshis(Blockchain.q("txfee/#{@hsh}"))
28
+ end
29
+
30
+ def ==(o)
31
+ o.instance_variables == self.instance_variables
32
+ end
33
+
34
+ class Input
35
+ attr_reader :script, :addr, :n, :tx_index
36
+
37
+ def initialize(i)
38
+ @script = i['script']
39
+ @prev_out = i['prev_out']
40
+ @addr = @prev_out['addr']
41
+ @n = @prev_out['n']
42
+ @tx_index = @prev_out['tx_index']
43
+ end
44
+
45
+ def prev_out
46
+ Transaction.find(@tx_index)
47
+ end
48
+ end
49
+
50
+ class Output
51
+ attr_reader :n, :addr, :tx_index, :spent, :type, :script
52
+
53
+ def initialize(o)
54
+ o.each_key { |k| instance_variable_set"@#{k}", o[k] }
55
+ @value = Btc.from_satoshis(@value)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe Blockchain::Address do
4
+
5
+ before :all do
6
+ FakeWeb.allow_net_connect = false
7
+ @test = '1AJbsFZ64EpEfS5UAjAfcUG8pH8Jn3rn1F'
8
+ fake_raw(TEST_ADDRESS)
9
+ @a = Blockchain::Address.find(@test)
10
+ end
11
+
12
+ it 'should get first seen' do
13
+ fake_q('addressfirstseen', '1331482301')
14
+ expect(@a.firstseen).to eq(DateTime.strptime('1331482301', '%s'))
15
+ end
16
+
17
+ it 'should init all fields' do
18
+ expect(@a.hash160).to eq('660d4ef3a743e3e696ad990364e555c271ad504b')
19
+ expect(@a.address).to eq('1AJbsFZ64EpEfS5UAjAfcUG8pH8Jn3rn1F')
20
+ expect(@a.n_tx).to eq(17)
21
+ expect(@a.n_unredeemed).to eq(2)
22
+ expect(@a.total_received).to eq(Btc.from_satoshis(1031350000))
23
+ expect(@a.total_sent).to eq(Btc.from_satoshis(931250000))
24
+ expect(@a.final_balance).to eq(Btc.from_satoshis(100100000))
25
+ expect(@a.txs).to eq([Blockchain::Transaction.new(JSON.parse(TEST_TRANSACTION))])
26
+ end
27
+
28
+ it 'should refresh to same thing' do
29
+ a1 = @a.clone
30
+ @a.refresh!
31
+ expect(@a).to eq(a1)
32
+ end
33
+
34
+ def fake_q(path, body, address = @test)
35
+ FakeWeb.register_uri(:get,
36
+ "#{Blockchain::ROOT}/q/#{path}/#{address}",
37
+ body: body, status: 200)
38
+ end
39
+
40
+ def fake_raw(body, address = @test)
41
+ FakeWeb.register_uri(:get,
42
+ "#{Blockchain::ROOT}/rawaddr/#{address}",
43
+ body: body, status: 200)
44
+ end
45
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Blockchain do
4
+
5
+ before(:each) do
6
+ FakeWeb.allow_net_connect = false
7
+ end
8
+
9
+ describe '.find' do
10
+ it 'should return nil if invalid raw block' do
11
+ FakeWeb.allow_net_connect = true
12
+ expect(Blockchain::Block.find('nonsense')).to be_nil
13
+ end
14
+
15
+ it 'it should init all fields' do
16
+ fake('someid', TEST_BLOCK)
17
+ b = Blockchain::Block.find('someid')
18
+ expect(b.hsh).to eq('0000000000000bae09a7a393a8acded75aa67e46cb81f7acaa5ad94f9eacd103')
19
+ expect(b.ver).to eq(1)
20
+ expect(b.prev_block).to eq('00000000000007d0f98d9edca880a6c124e25095712df8952e0439ac7409738a')
21
+ expect(b.mrkl_root).to eq('935aa0ed2e29a4b81e0c995c39e06995ecce7ddbebb26ed32d550a72e8200bf5')
22
+ expect(b.time).to eq(DateTime.strptime('1322131230', '%s'))
23
+ expect(b.bits).to eq(437129626)
24
+ expect(b.nonce).to eq(2964215930)
25
+ expect(b.n_tx).to eq(22)
26
+ expect(b.size).to eq(9195)
27
+ expect(b.block_index).to eq(818044)
28
+ expect(b.main_chain).to eq(true)
29
+ expect(b.height).to eq(154595)
30
+ expect(b.fee).to eq(Btc.from_satoshis(12345678))
31
+ expect(b.received_time).to eq(DateTime.strptime('1322131301', '%s'))
32
+ expect(b.relayed_by).to eq('108.60.208.156')
33
+ expect(b.tx).to eq([Blockchain::Transaction.new(JSON.parse(TEST_TRANSACTION))])
34
+ end
35
+ end
36
+
37
+ def fake(id, body)
38
+ FakeWeb.register_uri(:get, "#{Blockchain::ROOT}/rawblock/#{id}",
39
+ body: body, status: 200)
40
+ end
41
+
42
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Blockchain do
4
+
5
+ before :all do
6
+ FakeWeb.allow_net_connect = false
7
+ @test_i = 123456
8
+ @test_i_s = '123456'
9
+ @test_f = 12345.12345
10
+ @test_f_s = '12345.12345'
11
+ end
12
+
13
+ it 'should get difficulty' do
14
+ fake('getdifficulty', @test_f_s)
15
+ expect(Blockchain.difficulty.to_f).to eq(@test_f)
16
+ end
17
+
18
+ it 'should get blockcount' do
19
+ fake('getblockcount', @test_i_s)
20
+ expect(Blockchain.block_count).to eq(@test_i)
21
+ end
22
+
23
+ it 'should get latesthash' do
24
+ fake('latesthash', @test_i_s)
25
+ expect(Blockchain.latest_hash).to eq(@test_i_s)
26
+ end
27
+
28
+ it 'should get bcperblock' do
29
+ fake('bcperblock', @test_i_s)
30
+ expect(Blockchain.bc_per_block.btc.to_f).to eq(@test_i.to_f)
31
+ end
32
+
33
+ it 'should get total' do
34
+ fake('totalbc', @test_i_s)
35
+ expect(Blockchain.total.btc.to_f).to eq(@test_i.to_f)
36
+ end
37
+
38
+ it 'should get probability' do
39
+ fake('probability', @test_f_s)
40
+ expect(Blockchain.probability.to_f).to eq(@test_f)
41
+ end
42
+
43
+ it 'should get hashestowin' do
44
+ fake('hashestowin', @test_i_s)
45
+ expect(Blockchain.hashes_to_win).to eq(@test_i)
46
+ end
47
+
48
+ it 'should get nextretarget' do
49
+ fake('nextretarget', @test_i_s)
50
+ expect(Blockchain.next_retarget).to eq(@test_i)
51
+ end
52
+
53
+ it 'should get avg_tx_size' do
54
+ fake('avgtxsize', @test_i_s)
55
+ expect(Blockchain.avg_tx_size).to eq(@test_i)
56
+ end
57
+
58
+ it 'should get avg_tx_value' do
59
+ fake('avgtxvalue', @test_i_s)
60
+ expect(Blockchain.avg_tx_value).to eq(@test_i)
61
+ end
62
+
63
+ it 'should get avg_tx_number' do
64
+ fake('avgtxnumber', @test_i_s)
65
+ expect(Blockchain.avg_tx_number).to eq(@test_i)
66
+ end
67
+
68
+ it 'should get interval' do
69
+ fake('interval', @test_f_s)
70
+ expect(Blockchain.interval.to_f).to eq(@test_f)
71
+ end
72
+
73
+ it 'should get eta' do
74
+ fake('eta', @test_f_s)
75
+ expect(Blockchain.eta.to_f).to eq(@test_f)
76
+ end
77
+
78
+ def fake(path, body)
79
+ FakeWeb.register_uri(:get, "#{Blockchain::ROOT}/q/#{path}",
80
+ body: body, status: 200)
81
+ end
82
+ end
@@ -0,0 +1,84 @@
1
+ require 'fakeweb'
2
+ require 'blockchain'
3
+
4
+ TEST_TRANSACTION = <<-eos
5
+ {
6
+ "hash":"b6f6991d03df0e2e04dafffcd6bc418aac66049e2cd74b80f14ac86db1e3f0da",
7
+ "ver":1,
8
+ "vin_sz":1,
9
+ "vout_sz":2,
10
+ "time":1408744310,
11
+ "size":258,
12
+ "relayed_by":"64.179.201.80",
13
+ "block_height": 12200,
14
+ "tx_index":"12563028",
15
+ "result": 0,
16
+ "inputs":[
17
+ {
18
+ "prev_out":{
19
+ "n":1,
20
+ "addr":"143y8gQbhmgePi4QJyL6QBi8zk4PSM5KQr",
21
+ "value":"100000000",
22
+ "tx_index":12554260,
23
+ "type":0,
24
+ "script":"76a914641ad5051edd97029a003fe9efb29359fcee409d88ac"
25
+ },
26
+ "script":"76a914641ad5051edd97029a003fe9efb29359fcee409d88ac"
27
+ }
28
+ ],
29
+ "out":[
30
+ {
31
+ "n": 0,
32
+ "value": 100000,
33
+ "addr": "13s5H9qsCDxsbCuZF5mGbg6rMLziQAnrxr",
34
+ "tx_index": 62922222,
35
+ "spent": true,
36
+ "type": 0,
37
+ "script": "76a9141f689f046aae32021905eeec37baef94dd591ff588ac"
38
+ },
39
+ {
40
+ "n": 1,
41
+ "value": 1883055,
42
+ "addr": "143y8gQbhmgePi4QJyL6QBi8zk4PSM5KQr",
43
+ "tx_index": 62922222,
44
+ "spent": true,
45
+ "type": 0,
46
+ "script": "76a914217810f57fd7cdf79274c5d5e4a891fadc74887b88ac"
47
+ }
48
+ ]
49
+ }
50
+ eos
51
+
52
+ TEST_BLOCK = <<-eos
53
+ {
54
+ "hash":"0000000000000bae09a7a393a8acded75aa67e46cb81f7acaa5ad94f9eacd103",
55
+ "ver":1,
56
+ "prev_block":"00000000000007d0f98d9edca880a6c124e25095712df8952e0439ac7409738a",
57
+ "mrkl_root":"935aa0ed2e29a4b81e0c995c39e06995ecce7ddbebb26ed32d550a72e8200bf5",
58
+ "time":1322131230,
59
+ "bits":437129626,
60
+ "nonce":2964215930,
61
+ "fee":12345678,
62
+ "n_tx":22,
63
+ "size":9195,
64
+ "block_index":818044,
65
+ "main_chain":true,
66
+ "height":154595,
67
+ "received_time":1322131301,
68
+ "relayed_by":"108.60.208.156",
69
+ "tx": [#{TEST_TRANSACTION}]
70
+ }
71
+ eos
72
+
73
+ TEST_ADDRESS = <<-eos
74
+ {
75
+ "hash160":"660d4ef3a743e3e696ad990364e555c271ad504b",
76
+ "address":"1AJbsFZ64EpEfS5UAjAfcUG8pH8Jn3rn1F",
77
+ "n_tx":17,
78
+ "n_unredeemed":2,
79
+ "total_received":1031350000,
80
+ "total_sent":931250000,
81
+ "final_balance":100100000,
82
+ "txs": [#{TEST_TRANSACTION}]
83
+ }
84
+ eos
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ describe Blockchain::Transaction do
5
+
6
+ before :all do
7
+ FakeWeb.allow_net_connect = true
8
+ @test = 'b6f6991d03df0e2e04dafffcd6bc418aac66049e2cd74b80f14ac86db1e3f0da'
9
+ fake(@test, TEST_TRANSACTION)
10
+ @t = Blockchain::Transaction.find(@test)
11
+ end
12
+
13
+ it 'should return txtotalbtcoutput' do
14
+ fake_q("txtotalbtcoutput/#{@test}", '12345')
15
+ expect(@t.txtotalbtcoutput).to eq(Btc.from_satoshis('12345'))
16
+ end
17
+
18
+ it 'should return txtotalbtcinput' do
19
+ fake_q("txtotalbtcinput/#{@test}", '12345')
20
+ expect(@t.txtotalbtcinput).to eq(Btc.from_satoshis('12345'))
21
+ end
22
+
23
+ it 'should return txfee' do
24
+ fake_q("txfee/#{@test}", '12345')
25
+ expect(@t.txfee).to eq(Btc.from_satoshis('12345'))
26
+ end
27
+
28
+ it 'should parse and store all basic fields' do
29
+ expect(@t.hsh).to eq('b6f6991d03df0e2e04dafffcd6bc418aac66049e2cd74b80f14ac86db1e3f0da')
30
+ expect(@t.ver).to eq (1)
31
+ expect(@t.vin_sz).to eq(1)
32
+ expect(@t.vout_sz).to eq(2)
33
+ expect(@t.time).to eq(DateTime.strptime('1408744310', '%s'))
34
+ expect(@t.size).to eq(258)
35
+ expect(@t.relayed_by).to eq("64.179.201.80")
36
+ expect(@t.block_height).to eq(12200)
37
+ expect(@t.tx_index).to eq("12563028")
38
+ expect(@t.result).to eq(0)
39
+ expect(@t.double_spend).to be_falsey
40
+ end
41
+
42
+ describe Blockchain::Transaction::Input do
43
+ before :all do
44
+ @is = @t.inputs
45
+ end
46
+
47
+ it 'should assign prev out fields correctly' do
48
+ expect(@is[0].script).to eq('76a914641ad5051edd97029a003fe9efb29359fcee409d88ac')
49
+ expect(@is[0].addr).to eq('143y8gQbhmgePi4QJyL6QBi8zk4PSM5KQr')
50
+ expect(@is[0].n).to eq(1)
51
+ expect(@is[0].tx_index).to eq(12554260)
52
+ end
53
+
54
+ it 'should return prevout as a transaction' do
55
+ expect(@is[0].prev_out).to be_a(Blockchain::Transaction)
56
+ end
57
+
58
+ end
59
+
60
+ describe Blockchain::Transaction::Output do
61
+ before :all do
62
+ @os = @t.out
63
+ end
64
+
65
+ it 'should assign second out correctly' do
66
+ o = @os[1]
67
+ expect(o.n).to eq(1)
68
+ expect(o.addr).to eq('143y8gQbhmgePi4QJyL6QBi8zk4PSM5KQr')
69
+ expect(o.tx_index).to eq(62922222)
70
+ expect(o.spent).to eq(true)
71
+ expect(o.type).to eq(0)
72
+ expect(o.script).to eq('76a914217810f57fd7cdf79274c5d5e4a891fadc74887b88ac')
73
+ end
74
+ end
75
+
76
+ def fake(t, body)
77
+ FakeWeb.register_uri(:get,
78
+ "#{Blockchain::ROOT}/rawtx/#{t}",
79
+ body: body, status: 200)
80
+ end
81
+
82
+ def fake_q(path, body)
83
+ FakeWeb.register_uri(:get,
84
+ "#{Blockchain::ROOT}/q/#{path}",
85
+ body: body, status: 200)
86
+ end
87
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blockchain-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - James Larisch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: fakeweb
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.3.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.3.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: money
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 6.1.1
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 6.1.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: monetize
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.3.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.3.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: bitcoin-money
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.5.1
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.5.1
97
+ description: Convenient wrapper around public Blockchain.info API.
98
+ email:
99
+ - root@jameslarisch.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - Gemfile
106
+ - Gemfile.lock
107
+ - LICENSE.txt
108
+ - README.md
109
+ - blockchain-ruby.gemspec
110
+ - lib/address.rb
111
+ - lib/block.rb
112
+ - lib/blockchain.rb
113
+ - lib/realtime.rb
114
+ - lib/transaction.rb
115
+ - spec/address_spec.rb
116
+ - spec/block_spec.rb
117
+ - spec/reatime_spec.rb
118
+ - spec/spec_helper.rb
119
+ - spec/transaction_spec.rb
120
+ homepage: https://github.com/zenchilabs/blockchain-ruby
121
+ licenses: []
122
+ metadata: {}
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.2.2
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Convenient wrapper around public Blockchain.info API.
143
+ test_files:
144
+ - spec/address_spec.rb
145
+ - spec/block_spec.rb
146
+ - spec/reatime_spec.rb
147
+ - spec/spec_helper.rb
148
+ - spec/transaction_spec.rb
149
+ has_rdoc: