equestreum 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +18 -18
- data/README.md +50 -1
- data/config/equestreum.yaml +1 -1
- data/config/equestreum.yml +1 -0
- data/lib/config.rb +20 -0
- data/lib/equestreum/block.rb +16 -1
- data/lib/equestreum/chain.rb +79 -9
- data/lib/equestreum/config.rb +4 -6
- data/lib/equestreum/version.rb +1 -1
- data/lib/equestreum.rb +4 -2
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9998d629961146f004cbb807abedb73aedd6ff254043c1b96cc6da40138b2e06
|
4
|
+
data.tar.gz: 783f92d5422997ba62cf3a4ed8293f0309f4b842130d36963cfed657d70a1a5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9fa81e145bf4357da2e737c29d85f7b92ee0351938363df5b3e881b7710674e42bdf27c5eee89c62d04fb1d0b15a78b3a54d676c88684e44302942bb22ce9fc2
|
7
|
+
data.tar.gz: 7bad49b5c456efe912e996791cfb33f0c33b1020f0fd775e387c6727a64bb1e5a11e008410442649b1d426e894ccf8c772545dd9be9ecd440174da1e1a02799f
|
data/Gemfile.lock
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
equestreum (0.1.
|
4
|
+
equestreum (0.1.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
coderay (1.1.2)
|
10
|
-
coveralls (0.8.
|
10
|
+
coveralls (0.8.22)
|
11
11
|
json (>= 1.8, < 3)
|
12
|
-
simplecov (~> 0.
|
12
|
+
simplecov (~> 0.16.1)
|
13
13
|
term-ansicolor (~> 1.3)
|
14
14
|
thor (~> 0.19.4)
|
15
15
|
tins (~> 1.6)
|
16
16
|
diff-lcs (1.3)
|
17
|
-
docile (1.1
|
18
|
-
ffi (1.9.
|
17
|
+
docile (1.3.1)
|
18
|
+
ffi (1.9.25)
|
19
19
|
formatador (0.2.5)
|
20
20
|
guard (2.14.2)
|
21
21
|
formatador (>= 0.2.4)
|
@@ -49,23 +49,23 @@ GEM
|
|
49
49
|
rb-fsevent (0.10.3)
|
50
50
|
rb-inotify (0.9.10)
|
51
51
|
ffi (>= 0.5.0, < 2)
|
52
|
-
rspec (3.
|
53
|
-
rspec-core (~> 3.
|
54
|
-
rspec-expectations (~> 3.
|
55
|
-
rspec-mocks (~> 3.
|
56
|
-
rspec-core (3.
|
57
|
-
rspec-support (~> 3.
|
58
|
-
rspec-expectations (3.
|
52
|
+
rspec (3.8.0)
|
53
|
+
rspec-core (~> 3.8.0)
|
54
|
+
rspec-expectations (~> 3.8.0)
|
55
|
+
rspec-mocks (~> 3.8.0)
|
56
|
+
rspec-core (3.8.0)
|
57
|
+
rspec-support (~> 3.8.0)
|
58
|
+
rspec-expectations (3.8.1)
|
59
59
|
diff-lcs (>= 1.2.0, < 2.0)
|
60
|
-
rspec-support (~> 3.
|
61
|
-
rspec-mocks (3.
|
60
|
+
rspec-support (~> 3.8.0)
|
61
|
+
rspec-mocks (3.8.0)
|
62
62
|
diff-lcs (>= 1.2.0, < 2.0)
|
63
|
-
rspec-support (~> 3.
|
64
|
-
rspec-support (3.
|
63
|
+
rspec-support (~> 3.8.0)
|
64
|
+
rspec-support (3.8.0)
|
65
65
|
ruby_dep (1.5.0)
|
66
66
|
shellany (0.0.1)
|
67
|
-
simplecov (0.
|
68
|
-
docile (~> 1.1
|
67
|
+
simplecov (0.16.1)
|
68
|
+
docile (~> 1.1)
|
69
69
|
json (>= 1.8, < 3)
|
70
70
|
simplecov-html (~> 0.10.0)
|
71
71
|
simplecov-html (0.10.2)
|
data/README.md
CHANGED
@@ -1,6 +1,55 @@
|
|
1
|
+
[![Build Status](http://img.shields.io/travis/hat-festival/equestreum.svg?style=flat-square)](https://travis-ci.org/hat-festival/equestreum)
|
1
2
|
[![Coverage Status](http://img.shields.io/coveralls/hat-festival/equestreum.svg?style=flat-square)](https://coveralls.io/r/hat-festival/equestreum)
|
2
|
-
[![Code Climate](http://img.shields.io/codeclimate/github/hat-festival/equestreum.svg?style=flat-square)](https://codeclimate.com/github/hat-festival/equestreum)
|
3
3
|
[![Gem Version](http://img.shields.io/gem/v/equestreum.svg?style=flat-square)](https://rubygems.org/gems/equestreum)
|
4
4
|
[![License](http://img.shields.io/:license-mit-blue.svg?style=flat-square)](http://hat-festival.mit-license.org)
|
5
5
|
|
6
6
|
# Equestreum
|
7
|
+
|
8
|
+
## A blockchain for the [Voting Machine](//github.com/hat-festival/voting-machine)
|
9
|
+
|
10
|
+
We're trying to answer [one of the fundamental questions](//www.quora.com/Would-you-rather-fight-100-duck-sized-horses-or-one-horse-sized-duck), and we'd like to store the votes somewhere secure and stable. Unfortunately we don't have access to anything like that, so we built a blockchain instead
|
11
|
+
|
12
|
+
Starting with [this excellent tutorial](https://yukimotopress.github.io/programming-blockchains-step-by-step), this is about the simplest implementation of a blockchain that I could come up with
|
13
|
+
|
14
|
+
## How do I use it?
|
15
|
+
|
16
|
+
irb(main):001:0> require 'equestreum'
|
17
|
+
=> true
|
18
|
+
irb(main):002:0> chain = Equestreum::Chain.new do |c|
|
19
|
+
irb(main):003:1* c.path = '/tmp/shonky.chain'
|
20
|
+
irb(main):004:1> end
|
21
|
+
=> [#<Equestreum::Block:0x00007fd33d978660 @difficulty=3, @data="genesis block", @prev="0000000000000000000000000000000000000000000000000000000000000000", @time=1533992533, @nonce=9792, @hash="000a17e993e50496da998aabb67a5d88963979fc6f7c8ce552edb36f3fb2efea">]
|
22
|
+
irb(main):005:0> chain.first.data
|
23
|
+
=> "genesis block"
|
24
|
+
irb(main):006:0> chain.grow 'store this data'
|
25
|
+
=> [#<Equestreum::Block:0x00007fd33d978660 @difficulty=3, @data="genesis block", @prev="0000000000000000000000000000000000000000000000000000000000000000", @time=1533992533, @nonce=9792, @hash="000a17e993e50496da998aabb67a5d88963979fc6f7c8ce552edb36f3fb2efea">, #<Equestreum::Block:0x00007fd33d21fb48 @difficulty=3, @data="store this data", @prev="000a17e993e50496da998aabb67a5d88963979fc6f7c8ce552edb36f3fb2efea", @time=1533992533, @nonce=9525, @hash="0006d5dd01dc826a9f89446b3de097dabf5cb0fcf830ed32e25b9ee92696e16a">]
|
26
|
+
irb(main):007:0> chain.count
|
27
|
+
=> 2
|
28
|
+
irb(main):008:0> chain.verified?
|
29
|
+
=> true
|
30
|
+
irb(main):009:0> chain.difficulty
|
31
|
+
=> 3
|
32
|
+
irb(main):010:0> chain.difficulty = 4
|
33
|
+
=> 4
|
34
|
+
irb(main):011:0> chain.grow 'store some more data at a higher difficulty'
|
35
|
+
=> [#<Equestreum::Block:0x00007fd33d978660 @difficulty=3, @data="genesis block", @prev="0000000000000000000000000000000000000000000000000000000000000000", @time=1533992533, @nonce=9792, @hash="000a17e993e50496da998aabb67a5d88963979fc6f7c8ce552edb36f3fb2efea">, #<Equestreum::Block:0x00007fd33d21fb48 @difficulty=3, @data="store this data", @prev="000a17e993e50496da998aabb67a5d88963979fc6f7c8ce552edb36f3fb2efea", @time=1533992533, @nonce=9525, @hash="0006d5dd01dc826a9f89446b3de097dabf5cb0fcf830ed32e25b9ee92696e16a">, #<Equestreum::Block:0x00007fd33f019950 @difficulty=4, @data="store some more data at a higher difficulty", @prev="0006d5dd01dc826a9f89446b3de097dabf5cb0fcf830ed32e25b9ee92696e16a", @time=1533992534, @nonce=6484, @hash="0000bb78110c6d5d4404140fa5b64786a856485c4a98ebe0b3ff108f3c6111c8">]
|
36
|
+
irb(main):012:0> chain.save
|
37
|
+
=> 614
|
38
|
+
irb(main):013:0> c = Equestreum::Chain.revive
|
39
|
+
=> [#<Equestreum::Block:0x00007fd33d1a6900 @difficulty=3, @data="genesis block", @prev="0000000000000000000000000000000000000000000000000000000000000000", @time=1533992533, @nonce=9792, @hash="000a17e993e50496da998aabb67a5d88963979fc6f7c8ce552edb36f3fb2efea">, #<Equestreum::Block:0x00007fd33d1a64c8 @difficulty=3, @data="store this data", @prev="000a17e993e50496da998aabb67a5d88963979fc6f7c8ce552edb36f3fb2efea", @time=1533992533, @nonce=9525, @hash="0006d5dd01dc826a9f89446b3de097dabf5cb0fcf830ed32e25b9ee92696e16a">, #<Equestreum::Block:0x00007fd33d1a63b0 @difficulty=4, @data="store some more data at a higher difficulty", @prev="0006d5dd01dc826a9f89446b3de097dabf5cb0fcf830ed32e25b9ee92696e16a", @time=1533992534, @nonce=6484, @hash="0000bb78110c6d5d4404140fa5b64786a856485c4a98ebe0b3ff108f3c6111c8">]
|
40
|
+
irb(main):014:0> c.map { |b| b.data }
|
41
|
+
=> ["genesis block", "store this data", "store some more data at a higher difficulty"]
|
42
|
+
irb(main):015:0> c[1].data = 'this should be immutable'
|
43
|
+
=> "this should be immutable"
|
44
|
+
irb(main):016:0> begin
|
45
|
+
irb(main):017:1> c.verified?
|
46
|
+
irb(main):018:1> rescue Equestreum::EquestreumException => e
|
47
|
+
irb(main):019:1> puts e.text
|
48
|
+
irb(main):020:1> end
|
49
|
+
Block at 1 tampered with
|
50
|
+
=> nil
|
51
|
+
irb(main):021:0>
|
52
|
+
|
53
|
+
## Should I use it?
|
54
|
+
|
55
|
+
Fuck no
|
data/config/equestreum.yaml
CHANGED
@@ -1 +1 @@
|
|
1
|
-
chain_path:
|
1
|
+
chain_path: /usr/local/etc/equestreum.chain
|
@@ -0,0 +1 @@
|
|
1
|
+
chain_path: /usr/local/etc/equestreum.chain
|
data/lib/config.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Equestreum
|
2
|
+
class Config
|
3
|
+
include Singleton
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@config = fetch_yaml File.join(File.dirname(__FILE__), '..', '..', 'config/equestreum.yml')
|
7
|
+
@config.merge! fetch_yaml "#{ENV['HOME']}/.equestreum/config.yaml"
|
8
|
+
end
|
9
|
+
|
10
|
+
def config
|
11
|
+
@config
|
12
|
+
end
|
13
|
+
|
14
|
+
def fetch_yaml file
|
15
|
+
YAML.load_file file
|
16
|
+
rescue Errno::ENOENT
|
17
|
+
{}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/equestreum/block.rb
CHANGED
@@ -13,7 +13,7 @@ module Equestreum
|
|
13
13
|
@time = Time.now.to_i
|
14
14
|
@nonce = 0
|
15
15
|
loop do
|
16
|
-
@hash = Equestreum.hash @nonce, @difficulty, @prev, @data
|
16
|
+
@hash = Equestreum.hash @nonce, @time, @difficulty, @prev, @data
|
17
17
|
if Equestreum.difficulty_attained hash, @difficulty
|
18
18
|
break
|
19
19
|
else
|
@@ -21,5 +21,20 @@ module Equestreum
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
24
|
+
|
25
|
+
def to_h
|
26
|
+
h = {}
|
27
|
+
[
|
28
|
+
:data,
|
29
|
+
:time,
|
30
|
+
:hash,
|
31
|
+
:prev,
|
32
|
+
:nonce,
|
33
|
+
:difficulty
|
34
|
+
].each do |key|
|
35
|
+
h[key] = self.send(key)
|
36
|
+
end
|
37
|
+
h
|
38
|
+
end
|
24
39
|
end
|
25
40
|
end
|
data/lib/equestreum/chain.rb
CHANGED
@@ -1,23 +1,82 @@
|
|
1
1
|
module Equestreum
|
2
2
|
class Chain < Array
|
3
3
|
private :push, :append, :<<
|
4
|
+
attr_accessor :genesis_data, :difficulty, :path
|
4
5
|
|
5
|
-
def initialize
|
6
|
-
|
6
|
+
def initialize
|
7
|
+
@genesis_data = 'genesis block'
|
8
|
+
@difficulty = 3
|
9
|
+
@path = Config.instance.config['chain_path']
|
10
|
+
yield self if block_given?
|
11
|
+
|
12
|
+
grow @genesis_data,
|
13
|
+
prev: '0000000000000000000000000000000000000000000000000000000000000000'
|
14
|
+
end
|
15
|
+
|
16
|
+
def path= path
|
17
|
+
Config.instance.config['chain_path'] = path
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.difficulty= diff
|
21
|
+
c = self.revive
|
22
|
+
c.difficulty = diff
|
23
|
+
c.save
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.difficulty
|
27
|
+
self.revive.difficulty
|
7
28
|
end
|
8
29
|
|
9
|
-
def
|
30
|
+
def self.init difficulty: 3
|
31
|
+
diff = Config.instance.config['difficulty'] ? Config.instance.config['difficulty'] : difficulty
|
32
|
+
unless File.exists? Config.instance.config['chain_path']
|
33
|
+
chain = Chain.new do |c|
|
34
|
+
c.difficulty = diff
|
35
|
+
end
|
36
|
+
chain.save
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def grow data, prev: nil
|
10
41
|
block = Block.new do |b|
|
11
42
|
b.data = data
|
12
|
-
b.prev = self.last.hash
|
13
|
-
b.difficulty =
|
43
|
+
b.prev = prev ? prev : self.last.hash
|
44
|
+
b.difficulty = @difficulty
|
14
45
|
end
|
15
46
|
|
16
47
|
block.mine
|
17
|
-
|
18
48
|
push block
|
19
49
|
end
|
20
50
|
|
51
|
+
def self.grow data
|
52
|
+
chain = self.revive
|
53
|
+
chain.grow data
|
54
|
+
chain.save
|
55
|
+
|
56
|
+
chain
|
57
|
+
end
|
58
|
+
|
59
|
+
def data with_genesis: false
|
60
|
+
data = self.map do |b|
|
61
|
+
{
|
62
|
+
datetime: Time.at(b.time).iso8601,
|
63
|
+
data: b.data
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
data.shift unless with_genesis
|
68
|
+
|
69
|
+
data
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.aggregate
|
73
|
+
h = Hash.new 0
|
74
|
+
Chain.revive[1..-1].each do |block|
|
75
|
+
h[block.data] += 1
|
76
|
+
end
|
77
|
+
h
|
78
|
+
end
|
79
|
+
|
21
80
|
def hash_ok? index
|
22
81
|
block = self[index]
|
23
82
|
|
@@ -32,7 +91,9 @@ module Equestreum
|
|
32
91
|
|
33
92
|
def hashes_ok?
|
34
93
|
self.length.times do |index|
|
35
|
-
|
94
|
+
unless hash_ok? index
|
95
|
+
raise EquestreumException.new "Block at #{index} tampered with"
|
96
|
+
end
|
36
97
|
end
|
37
98
|
true
|
38
99
|
end
|
@@ -67,7 +128,7 @@ module Equestreum
|
|
67
128
|
return true if index == 0
|
68
129
|
block = self[index]
|
69
130
|
previous = self[index - 1]
|
70
|
-
block.time
|
131
|
+
block.time >= previous.time
|
71
132
|
end
|
72
133
|
|
73
134
|
def blocks_get_newer?
|
@@ -77,14 +138,23 @@ module Equestreum
|
|
77
138
|
true
|
78
139
|
end
|
79
140
|
|
141
|
+
def verified?
|
142
|
+
hashes_ok? && proofs_of_work_ok? && previous_hashes_ok? && blocks_get_newer?
|
143
|
+
end
|
144
|
+
|
80
145
|
def save
|
146
|
+
FileUtils.mkdir_p File.dirname Config.instance.config['chain_path']
|
81
147
|
File.open Config.instance.config['chain_path'], 'w' do |f|
|
82
148
|
f.write Marshal.dump self
|
83
149
|
end
|
84
150
|
end
|
85
151
|
|
86
152
|
def self.revive
|
87
|
-
|
153
|
+
begin
|
154
|
+
Marshal.load File.read Config.instance.config['chain_path']
|
155
|
+
rescue Errno::ENOENT
|
156
|
+
raise EquestreumException.new "no chain found at #{Config.instance.config['chain_path']}"
|
157
|
+
end
|
88
158
|
end
|
89
159
|
end
|
90
160
|
end
|
data/lib/equestreum/config.rb
CHANGED
@@ -2,9 +2,9 @@ module Equestreum
|
|
2
2
|
class Config
|
3
3
|
include Singleton
|
4
4
|
|
5
|
-
def initialize
|
6
|
-
@config = fetch_yaml File.join(File.dirname(__FILE__), '..', '..', 'config/equestreum.
|
7
|
-
@config.merge! fetch_yaml
|
5
|
+
def initialize
|
6
|
+
@config = fetch_yaml File.join(File.dirname(__FILE__), '..', '..', 'config/equestreum.yml')
|
7
|
+
@config.merge! fetch_yaml 'config/equestreum.yml' if File.exists? 'config/equestreum.yml'
|
8
8
|
end
|
9
9
|
|
10
10
|
def config
|
@@ -12,9 +12,7 @@ module Equestreum
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def fetch_yaml file
|
15
|
-
YAML.
|
16
|
-
rescue Errno::ENOENT
|
17
|
-
{}
|
15
|
+
YAML.load_file file
|
18
16
|
end
|
19
17
|
end
|
20
18
|
end
|
data/lib/equestreum/version.rb
CHANGED
data/lib/equestreum.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'digest'
|
2
|
+
require 'singleton'
|
3
|
+
require 'yaml'
|
2
4
|
|
3
5
|
require 'equestreum/version'
|
4
6
|
require 'equestreum/config'
|
@@ -6,10 +8,10 @@ require 'equestreum/block'
|
|
6
8
|
require 'equestreum/chain'
|
7
9
|
|
8
10
|
module Equestreum
|
9
|
-
def self.hash nonce, difficulty, prev, data
|
11
|
+
def self.hash nonce, time, difficulty, prev, data
|
10
12
|
string = '%s%s%s%s%s' % [
|
11
13
|
nonce,
|
12
|
-
|
14
|
+
time,
|
13
15
|
'0' * difficulty,
|
14
16
|
prev,
|
15
17
|
data
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: equestreum
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- pikesley
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-08-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -114,7 +114,9 @@ files:
|
|
114
114
|
- bin/console
|
115
115
|
- bin/setup
|
116
116
|
- config/equestreum.yaml
|
117
|
+
- config/equestreum.yml
|
117
118
|
- equestreum.gemspec
|
119
|
+
- lib/config.rb
|
118
120
|
- lib/equestreum.rb
|
119
121
|
- lib/equestreum/block.rb
|
120
122
|
- lib/equestreum/chain.rb
|