utxoracle 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e06742e7448c182f3f2399e200c50e0563f3d8672433d942028cbc7c1827f60b
4
- data.tar.gz: 33f2c9d1d7e496664c84a682e3b0d09a0971f152f7f351b59d7cdeb0baa48bba
3
+ metadata.gz: 966c4c18a2b785a539acbfd09a9b491b24d5e83b6b606e5db05f4f3997c3f13c
4
+ data.tar.gz: 6089c1e572294e3b0a2a0c5f1e842f5b52449d78001522fe1f5c6c3db1c3382e
5
5
  SHA512:
6
- metadata.gz: b64d8799da84d9ee041e61548adcf889067bd0bcef7b5331d59e43aca4bec7a4075d6bdd0773939132d9b8dec4b428e60a05be9bf9b720ecfec74b40b805e74f
7
- data.tar.gz: caeb20a9d134903c29cccfd3bd03697a1bcf5b56452762ea383850b9423a4bc056d7ac77e4d18ed6f455d7765e21935421172ccd2ab3ca733298545792a03628
6
+ metadata.gz: 9cbde112559f59680e49d3fbef85dee93660b2ca03f3c8c73c45d07565ec6f90871e00de939ff530ce0a63f53e8fad3ef0c0b8e338e60d05aae9628fb72af971
7
+ data.tar.gz: 592eaf022a3bdfd81856cb9dfe1a6ee822daaf71d43bd824f7dd39e88d6b192cf17bb6d7d42f1a27368de5417ff8bbbbaa33c0a1e908e5b492427ae94a91a709
data/README.md CHANGED
@@ -1,7 +1,17 @@
1
- # UTXOracle.rb
2
- Ruby implementation of https://utxo.live/oracle/.
1
+ [![Gem Version](https://badge.fury.io/rb/utxoracle.svg)](https://badge.fury.io/rb/utxoracle)
2
+
3
+ # Utxoracle
4
+ Offline price oracle for Bitcoin written in Ruby.
5
+
6
+ In September 2023 [SteveSimple](https://twitter.com/SteveSimple) & [DanielLHinton](https://twitter.com/DanielLHinton) [dropped](https://twitter.com/SteveSimple/status/1704864674431332503) https://utxo.live/oracle/, the first method to derive historical USD price of bitcoin based purely on UTXO set.
7
+
8
+ Needless to say, a lot of bitcoiners found this VERY cool. We're in a unique phase of history; transitioning from the Dollar Network to a Bitcoin Standard. Pulling out these patterns sparks joy.
9
+
10
+ The purpose of releasing Utxoracle as a Gem is multi-fold:
11
+ 1. Make the tool available as a [Gem](https://rubygems.org/gems/utxoracle) to the Ruby community.
12
+ 2. Provide a flexible API, where folks can extend this for other use cases (currencies, language, etc).
13
+ 3. Provide a _modular_ provider model, so folks can pull data from mempool.space or other RPCs.
3
14
 
4
- (Original implementation by [SteveSimple](https://twitter.com/SteveSimple) & [DanielLHinton](https://twitter.com/DanielLHinton) who discovered and built the first offline bitcoin price oracle.)
5
15
 
6
16
  ## Table of contents
7
17
 
@@ -37,14 +47,14 @@ require 'utxoracle'
37
47
 
38
48
  ### Fetching price
39
49
 
40
- #### Using a raw bitcoin node
50
+ #### Using a specific bitcoin node
41
51
  ```ruby
42
- provider = Utxoracle::RawBitcoinNode.new("aUser", "aPassword", "127.0.0.1", 8332)
52
+ provider = Utxoracle::Node.new("aUser", "aPassword", "127.0.0.1", 8332)
43
53
  ```
44
54
 
45
55
  #### Using mempool.space node
46
56
  ```ruby
47
- provider = Utxoracle::MempoolDotSpace.new
57
+ provider = Utxoracle::Mempool.new
48
58
  ```
49
59
 
50
60
  ####
data/Rakefile CHANGED
@@ -1,4 +1,4 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
2
  require 'rubocop/rake_task'
3
3
  require 'rspec/core/rake_task'
4
4
 
data/bin/run ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'utxoracle'
6
+
7
+ user = ARGV[0]
8
+ password = ARGV[1]
9
+ ip = ARGV[2]
10
+ port = ARGV[3]
11
+ date = ARGV[4]
12
+
13
+ provider = Utxoracle::Node.new(user, password, ip, port)
14
+ oracle = Utxoracle::Oracle.new(provider, true)
15
+ oracle.price(date)
@@ -1,6 +1,5 @@
1
1
  require 'time'
2
2
  require_relative 'rpc'
3
- require_relative 'providers/raw_bitcoin_node'
4
3
 
5
4
  module Utxoracle
6
5
  class Oracle
@@ -19,12 +18,14 @@ module Utxoracle
19
18
 
20
19
  def price(requested_date)
21
20
  unless validate_date(requested_date)
22
- puts "Invalid date.\nEarliest available: 2020-07-26.\nLatest available #{Date.today}.\nFormat: YYYY-MM-DD."
23
- return
21
+ if @log
22
+ puts "Invalid date.\nEarliest available: 2020-07-26.\nLatest available #{Date.today}.\nFormat: YYYY-MM-DD."
23
+ end
24
+ return -1
24
25
  end
25
26
 
26
27
  if price_estimate = @cache[requested_date]
27
- puts "price_estimate is #{price_estimate}"
28
+ puts "price_estimate is #{price_estimate}" if @log
28
29
  return price_estimate
29
30
  end
30
31
 
@@ -124,7 +125,7 @@ module Utxoracle
124
125
 
125
126
  puts("Reading all blocks on #{price_day_date_utc}...") if @log
126
127
  puts('This will take a few minutes (~144 blocks)...') if @log
127
- puts("Height\tTime(utc)\t Completion %") if @log
128
+ puts("Height\tTime(utc)\tCompletion %") if @log
128
129
 
129
130
  block_height = price_day_block_estimate
130
131
  block_hash_b = @provider.getblockhash(block_height)
@@ -143,8 +144,8 @@ module Utxoracle
143
144
  while target == day
144
145
  blocks_on_this_day += 1
145
146
 
146
- progress_estimate = 100.0 * (hour + minute / 60) / 24.0
147
- puts("#{block_height}\t#{time.strftime('%H:%M:%S')}\t#{progress_estimate}") if @log
147
+ progress_estimate = 100.0 * (hour + minute / 60.0) / 24.0
148
+ puts("#{block_height}\t#{time.strftime('%H:%M:%S')}\t#{progress_estimate.round(2)}") if @log
148
149
 
149
150
  for tx in block_b['tx']
150
151
  outputs = tx['vout']
@@ -347,6 +348,8 @@ module Utxoracle
347
348
  (Date.parse(date) < Date.today)
348
349
 
349
350
  valid_format && valid_range
351
+ rescue Date::Error
352
+ false
350
353
  end
351
354
  end
352
355
  end
@@ -5,7 +5,7 @@ require_relative '../request'
5
5
  # and throttles the number of requests the oracle takes to compute.
6
6
  # Running this requires an Enterprise license.
7
7
  module Utxoracle
8
- class MempoolDotSpace < Provider
8
+ class Mempool < Provider
9
9
  def initialize; end
10
10
 
11
11
  def getblockcount
@@ -2,7 +2,7 @@ require_relative '../provider'
2
2
  require_relative '../rpc'
3
3
 
4
4
  module Utxoracle
5
- class RawBitcoinNode < Provider
5
+ class Node < Provider
6
6
  def initialize(rpcuser, rpcpassword, ip, port)
7
7
  @rpc = Rpc.new("http://#{rpcuser}:#{rpcpassword}@#{ip}:#{port}")
8
8
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Utxoracle
4
- VERSION = '0.0.1'
4
+ VERSION = '0.0.2'
5
5
  end
data/lib/utxoracle.rb CHANGED
@@ -3,8 +3,8 @@
3
3
  require_relative 'utxoracle/rpc'
4
4
  require_relative 'utxoracle/version'
5
5
  require_relative 'utxoracle/oracle'
6
- require_relative 'utxoracle/providers/mempool_dot_space'
7
- require_relative 'utxoracle/providers/raw_bitcoin_node'
6
+ require_relative 'utxoracle/providers/mempool'
7
+ require_relative 'utxoracle/providers/node'
8
8
 
9
9
  module Utxoracle
10
10
  end
@@ -2,20 +2,38 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- # RSpec.describe Utxoracle::Oracle do
6
- # let(:oracle) do
7
- # described_class.new('aUser', 'aPassword', '127.0.0.1', '8332')
8
- # end
9
- #
10
- # describe '.new' do
11
- # it 'initialized an Rpc instance' do
12
- # expect(Utxoracle::Rpc).to receive(:new)
13
- # described_class.new('aUser', 'aPassword', '127.0.0.1', '8332')
14
- # expect(oracle.class).to eq Utxoracle::Oracle
15
- # end
16
- # end
17
- #
18
- # # TODO: - test cache
19
- # # TODO - test provider interface
20
- # # TODO - test `price` return type
21
- # end
5
+ RSpec.describe Utxoracle::Oracle do
6
+ describe '.new' do
7
+ it 'requires provider and takes optional log config' do
8
+ provider = Utxoracle::Mempool
9
+ Utxoracle::Oracle.new(provider, log = true)
10
+ end
11
+ end
12
+
13
+ describe 'date validation' do
14
+ it 'returns -1 for garbage date inputs' do
15
+ provider = Utxoracle::Mempool
16
+ oracle = Utxoracle::Oracle.new(provider)
17
+ price = oracle.price('garbage')
18
+ expect(price).to be(-1)
19
+ end
20
+
21
+ it 'returns -1 for dates before 2020-07-26' do
22
+ provider = Utxoracle::Mempool
23
+ oracle = Utxoracle::Oracle.new(provider)
24
+ price = oracle.price('2015-01-01')
25
+ expect(price).to be(-1)
26
+ end
27
+
28
+ it 'returns -1 for dates in the future' do
29
+ provider = Utxoracle::Mempool
30
+ oracle = Utxoracle::Oracle.new(provider)
31
+ price = oracle.price('3000-01-01')
32
+ expect(price).to be(-1)
33
+ end
34
+ end
35
+
36
+ # TODO: - test cache
37
+ # TODO - test provider interface
38
+ # TODO - test `price` return type
39
+ end
@@ -6,6 +6,7 @@ RSpec.describe Utxoracle::Rpc do
6
6
  let(:rpc) do
7
7
  described_class.new('http://foo:bar@127.0.0.1:8332')
8
8
  end
9
+
9
10
  describe '.new' do
10
11
  it 'creates an instance of Rpc with given uri' do
11
12
  expect(rpc.class).to eq(Utxoracle::Rpc)
@@ -18,12 +19,16 @@ RSpec.describe Utxoracle::Rpc do
18
19
  end
19
20
 
20
21
  it 'forwards methods over http' do
21
- allow(rpc).to receive(:http_post_request).and_return("{\"result\":814521,\"error\":null,\"id\":\"jsonrpc\"}\n")
22
+ allow(rpc).to receive(:http_post_request).and_return(
23
+ "{\"result\":814521,\"error\":null,\"id\":\"jsonrpc\"}\n"
24
+ )
22
25
  expect(rpc.getblockcount).to eq 814_521
23
26
  end
24
27
 
25
28
  it 'returns error from http endpoint when indicated' do
26
- expect(rpc).to receive(:http_post_request).and_return("{\"result\":814521,\"error\":\"test error\",\"id\":\"jsonrpc\"}\n")
29
+ expect(rpc).to receive(:http_post_request).and_return(
30
+ "{\"result\":814521,\"error\":\"test error\",\"id\":\"jsonrpc\"}\n"
31
+ )
27
32
  expect { rpc.test_rpc_call }.to raise_error(Utxoracle::Rpc::JSONRPCError)
28
33
  end
29
34
  end
data/utxoracle.gemspec CHANGED
@@ -11,17 +11,17 @@ Gem::Specification.new do |spec|
11
11
  spec.platform = Gem::Platform::RUBY
12
12
  spec.authors = ['Keith Gardner']
13
13
 
14
- spec.summary = 'Interface for UTXOracle.'
15
- spec.description = 'Object oriented design for interacting with UTXOracle.'
14
+ spec.summary = 'Offline price oracle for Bitcoin.'
15
+ spec.description = 'Offline price oracle for Bitcoin. Offers programmable data providers (Bitcoin node, mempool, etc). Can be used from commandline, or integrated into existing ruby stacks.'
16
16
  spec.homepage = 'https://github.com/Carolina-Bitcoin-Project/UTXOracle'
17
17
  spec.license = 'MIT'
18
18
  spec.required_ruby_version = '>= 3.1.0'
19
19
 
20
20
  spec.files = `git ls-files`.split("\n")
21
- spec.bindir = 'exe'
21
+ spec.bindir = 'bin'
22
22
  spec.require_path = 'lib'
23
23
 
24
- spec.add_dependency 'typhoeus'
24
+ spec.add_dependency 'typhoeus', '~> 1.4.0'
25
25
 
26
26
  spec.add_development_dependency 'pry'
27
27
  spec.add_development_dependency 'rake'
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: utxoracle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keith Gardner
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-01 00:00:00.000000000 Z
11
+ date: 2023-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 1.4.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: 1.4.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pry
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -122,26 +122,27 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
- description: Object oriented design for interacting with UTXOracle.
125
+ description: Offline price oracle for Bitcoin. Offers programmable data providers
126
+ (Bitcoin node, mempool, etc). Can be used from commandline, or integrated into existing
127
+ ruby stacks.
126
128
  email:
127
129
  executables: []
128
130
  extensions: []
129
131
  extra_rdoc_files: []
130
132
  files:
131
133
  - ".gitignore"
132
- - ".rspec"
133
- - ".rspec_status"
134
134
  - ".ruby-version"
135
135
  - Gemfile
136
136
  - LICENSE
137
137
  - README.md
138
138
  - Rakefile
139
139
  - bin/console
140
+ - bin/run
140
141
  - lib/utxoracle.rb
141
142
  - lib/utxoracle/oracle.rb
142
143
  - lib/utxoracle/provider.rb
143
- - lib/utxoracle/providers/mempool_dot_space.rb
144
- - lib/utxoracle/providers/raw_bitcoin_node.rb
144
+ - lib/utxoracle/providers/mempool.rb
145
+ - lib/utxoracle/providers/node.rb
145
146
  - lib/utxoracle/request.rb
146
147
  - lib/utxoracle/rpc.rb
147
148
  - lib/utxoracle/version.rb
@@ -172,5 +173,5 @@ requirements: []
172
173
  rubygems_version: 3.4.10
173
174
  signing_key:
174
175
  specification_version: 4
175
- summary: Interface for UTXOracle.
176
+ summary: Offline price oracle for Bitcoin.
176
177
  test_files: []
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rspec_status DELETED
@@ -1,8 +0,0 @@
1
- example_id | status | run_time |
2
- -------------------------------------- | ------ | --------------- |
3
- ./spec/utxoracle/oracle_spec.rb[1:1:1] | failed | 0.00966 seconds |
4
- ./spec/utxoracle/rpc_spec.rb[1:1:1] | passed | 0.00025 seconds |
5
- ./spec/utxoracle/rpc_spec.rb[1:2] | passed | 0.01109 seconds |
6
- ./spec/utxoracle/rpc_spec.rb[1:3] | passed | 0.00028 seconds |
7
- ./spec/utxoracle/rpc_spec.rb[1:4] | passed | 0.00214 seconds |
8
- ./spec/utxoracle_spec.rb[1:1] | passed | 0.00127 seconds |