utxoracle 0.0.1 → 0.0.2
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 +4 -4
- data/README.md +16 -6
- data/Rakefile +1 -1
- data/bin/run +15 -0
- data/lib/utxoracle/oracle.rb +10 -7
- data/lib/utxoracle/providers/{mempool_dot_space.rb → mempool.rb} +1 -1
- data/lib/utxoracle/providers/{raw_bitcoin_node.rb → node.rb} +1 -1
- data/lib/utxoracle/version.rb +1 -1
- data/lib/utxoracle.rb +2 -2
- data/spec/utxoracle/oracle_spec.rb +35 -17
- data/spec/utxoracle/rpc_spec.rb +7 -2
- data/utxoracle.gemspec +4 -4
- metadata +14 -13
- data/.rspec +0 -3
- data/.rspec_status +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 966c4c18a2b785a539acbfd09a9b491b24d5e83b6b606e5db05f4f3997c3f13c
|
4
|
+
data.tar.gz: 6089c1e572294e3b0a2a0c5f1e842f5b52449d78001522fe1f5c6c3db1c3382e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9cbde112559f59680e49d3fbef85dee93660b2ca03f3c8c73c45d07565ec6f90871e00de939ff530ce0a63f53e8fad3ef0c0b8e338e60d05aae9628fb72af971
|
7
|
+
data.tar.gz: 592eaf022a3bdfd81856cb9dfe1a6ee822daaf71d43bd824f7dd39e88d6b192cf17bb6d7d42f1a27368de5417ff8bbbbaa33c0a1e908e5b492427ae94a91a709
|
data/README.md
CHANGED
@@ -1,7 +1,17 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
[](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
|
50
|
+
#### Using a specific bitcoin node
|
41
51
|
```ruby
|
42
|
-
provider = Utxoracle::
|
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::
|
57
|
+
provider = Utxoracle::Mempool.new
|
48
58
|
```
|
49
59
|
|
50
60
|
####
|
data/Rakefile
CHANGED
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)
|
data/lib/utxoracle/oracle.rb
CHANGED
@@ -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
|
-
|
23
|
-
|
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)\
|
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
|
8
|
+
class Mempool < Provider
|
9
9
|
def initialize; end
|
10
10
|
|
11
11
|
def getblockcount
|
data/lib/utxoracle/version.rb
CHANGED
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/
|
7
|
-
require_relative 'utxoracle/providers/
|
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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
data/spec/utxoracle/rpc_spec.rb
CHANGED
@@ -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(
|
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(
|
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 = '
|
15
|
-
spec.description = '
|
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 = '
|
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.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keith Gardner
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-11-
|
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:
|
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:
|
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:
|
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/
|
144
|
-
- lib/utxoracle/providers/
|
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:
|
176
|
+
summary: Offline price oracle for Bitcoin.
|
176
177
|
test_files: []
|
data/.rspec
DELETED
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 |
|