blockchain-ruby 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: