centralbank 0.2.1 → 0.2.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 +5 -5
- data/{HISTORY.md → CHANGELOG.md} +0 -0
- data/Manifest.txt +1 -2
- data/README.md +122 -112
- data/Rakefile +2 -2
- data/lib/centralbank/bank.rb +109 -109
- data/lib/centralbank/block.rb +44 -44
- data/lib/centralbank/cache.rb +22 -22
- data/lib/centralbank/ledger.rb +30 -30
- data/lib/centralbank/node.rb +82 -82
- data/lib/centralbank/service.rb +2 -2
- data/lib/centralbank/transaction.rb +30 -30
- data/lib/centralbank/version.rb +2 -2
- data/lib/centralbank/views/index.erb +30 -30
- data/lib/centralbank/views/style.scss +172 -172
- data/lib/centralbank/wallet.rb +15 -15
- metadata +19 -16
- data/LICENSE.md +0 -116
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 88f50459e3ecf1ffde61049250241fd50a9bd059662e3c823243ca74413ce6d6
|
|
4
|
+
data.tar.gz: bf0ebbf7e3d723e195f8cbc2eef52784a8d05340a782070dd2fd65b78fdba129
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ff627e08bec25b65d1d40dff8c40d73cc20cb2cab1ba6b3852159709c6ec7521e6bf0f6e5d4974ce7801b6f00c97162be2f1f9d3877b500fd7aab16e162d7c0f
|
|
7
|
+
data.tar.gz: 31c6a909d89ca88496f93134a8eb24b2b860f7d7e3e5f6bc14fc642f3319804ac509e77406193e15e94266aabe3fb74e9cb017c8005590f5b3534cb3391e1c97
|
data/{HISTORY.md → CHANGELOG.md}
RENAMED
|
File without changes
|
data/Manifest.txt
CHANGED
data/README.md
CHANGED
|
@@ -1,112 +1,122 @@
|
|
|
1
|
-
# centralbank
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
!
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
a different
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
gem '
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
1
|
+
# centralbank
|
|
2
|
+
|
|
3
|
+
central bank library / gem and command line tool -
|
|
4
|
+
print your own money / cryptocurrency; run your own federated central bank nodes on the blockchain peer-to-peer over HTTP; revolutionize the world one block at a time
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
* home :: [github.com/rubycoco/blockchain](https://github.com/rubycoco/blockchain)
|
|
8
|
+
* bugs :: [github.com/rubycoco/blockchain/issues](https://github.com/rubycoco/blockchain/issues)
|
|
9
|
+
* gem :: [rubygems.org/gems/centralbank](https://rubygems.org/gems/centralbank)
|
|
10
|
+
* rdoc :: [rubydoc.info/gems/centralbank](http://rubydoc.info/gems/centralbank)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## Command Line
|
|
15
|
+
|
|
16
|
+
Use the `centralbank` command line tool. Try:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
$ centralbank -h
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
resulting in:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
Usage: centralbank [options]
|
|
26
|
+
|
|
27
|
+
Wallet options:
|
|
28
|
+
-n, --name=NAME Address name (default: Alice)
|
|
29
|
+
|
|
30
|
+
Server (node) options:
|
|
31
|
+
-o, --host HOST listen on HOST (default: 0.0.0.0)
|
|
32
|
+
-p, --port PORT use PORT (default: 4567)
|
|
33
|
+
-h, --help Prints this help
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
To start a new (network) node using the default wallet
|
|
37
|
+
address (that is, Alice) and the default server host and port settings
|
|
38
|
+
use:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
$ centralbank
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Stand back ten feets :-) while starting up the machinery.
|
|
45
|
+
Ready to print (mine) money on the blockchain?
|
|
46
|
+
In your browser open up the page e.g. `http://localhost:4567`. Voila!
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
Note: You can start a second node on your computer -
|
|
53
|
+
make sure to use a different port (use the `-p/--port` option)
|
|
54
|
+
and (recommended)
|
|
55
|
+
a different wallet address (use the `-n/--name` option).
|
|
56
|
+
Example:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
$ centralbank -p 5678 -n Bob
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Happy mining!
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
## Local Development Setup
|
|
67
|
+
|
|
68
|
+
For local development - clone or download (and unzip) the centralbank code repo.
|
|
69
|
+
Next install all dependencies using bundler with a Gemfile e.g.:
|
|
70
|
+
|
|
71
|
+
``` ruby
|
|
72
|
+
# Gemfile
|
|
73
|
+
|
|
74
|
+
source "https://rubygems.org"
|
|
75
|
+
|
|
76
|
+
gem 'sinatra'
|
|
77
|
+
gem 'sass'
|
|
78
|
+
gem 'blockchain-lite'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
run
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
$ bundle ## will use the Gemfile (see above)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
and now you're ready to run your own centralbank server node. Use the [`config.ru`](config.ru) script for rack:
|
|
88
|
+
|
|
89
|
+
``` ruby
|
|
90
|
+
# config.ru
|
|
91
|
+
|
|
92
|
+
$LOAD_PATH << './lib'
|
|
93
|
+
|
|
94
|
+
require 'centralbank'
|
|
95
|
+
|
|
96
|
+
run Centralbank::Service
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
and startup the money printing machine using rackup - the rack command line tool:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
$ rackup ## will use the config.ru - rackup configuration script (see above).
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
In your browser open up the page e.g. `http://localhost:9292`. Voila! Happy mining!
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
## References
|
|
111
|
+
|
|
112
|
+
[**Programming Cryptocurrencies and Blockchains (in Ruby)**](http://yukimotopress.github.io/blockchains) by Gerald Bauer et al, 2018, Yuki & Moto Press
|
|
113
|
+
|
|
114
|
+
And many more @ [**Best of Crypto Books**](https://openblockchains.github.io/crypto-books/) - a collection of books, white papers & more about crypto and blockchains
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+

|
|
120
|
+
|
|
121
|
+
The `centralbank` scripts are dedicated to the public domain.
|
|
122
|
+
Use it as you please with no restrictions whatsoever.
|
data/Rakefile
CHANGED
|
@@ -8,14 +8,14 @@ Hoe.spec 'centralbank' do
|
|
|
8
8
|
self.summary = 'centralbank - print your own money / cryptocurrency; run your own federated central bank nodes on the blockchain peer-to-peer over HTTP; revolutionize the world one block at a time'
|
|
9
9
|
self.description = summary
|
|
10
10
|
|
|
11
|
-
self.urls =
|
|
11
|
+
self.urls = { home: 'https://github.com/rubycoco/blockchain' }
|
|
12
12
|
|
|
13
13
|
self.author = 'Gerald Bauer'
|
|
14
14
|
self.email = 'ruby-talk@ruby-lang.org'
|
|
15
15
|
|
|
16
16
|
# switch extension to .markdown for gihub formatting
|
|
17
17
|
self.readme_file = 'README.md'
|
|
18
|
-
self.history_file = '
|
|
18
|
+
self.history_file = 'CHANGELOG.md'
|
|
19
19
|
|
|
20
20
|
self.extra_deps = [
|
|
21
21
|
['sinatra', '>=2.0'],
|
data/lib/centralbank/bank.rb
CHANGED
|
@@ -1,109 +1,109 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
class Bank
|
|
4
|
-
attr_reader :pending, :chain, :ledger
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def initialize( address )
|
|
8
|
-
@address = address
|
|
9
|
-
|
|
10
|
-
## note: add address name for now to cache
|
|
11
|
-
## allows to start more nodes in same folder / directory
|
|
12
|
-
@cache = Cache.new( "data.#{address.downcase}.json" )
|
|
13
|
-
h = @cache.read
|
|
14
|
-
if h
|
|
15
|
-
## restore blockchain
|
|
16
|
-
@chain = Blockchain.from_json( h['chain'] )
|
|
17
|
-
## restore pending (unconfirmed) transactions pool too
|
|
18
|
-
@pending = Pool.from_json( h['transactions'] )
|
|
19
|
-
else
|
|
20
|
-
@chain = Blockchain.new
|
|
21
|
-
@chain << [Tx.new( Centralbank.config.rand_coinbase,
|
|
22
|
-
@address,
|
|
23
|
-
Centralbank.config.mining_reward )] # genesis (big bang!) starter block
|
|
24
|
-
@pending = Pool.new
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
## update ledger (balances) with confirmed transactions
|
|
28
|
-
@ledger = Ledger.new( @chain )
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def mine_block!
|
|
34
|
-
add_transaction( Tx.new( Centralbank.config.rand_coinbase,
|
|
35
|
-
@address,
|
|
36
|
-
Centralbank.config.mining_reward ))
|
|
37
|
-
|
|
38
|
-
## add mined (w/ computed/calculated hash) block
|
|
39
|
-
@chain << @pending.transactions
|
|
40
|
-
@pending = Pool.new ## clear out/ empty pool (just create a new one for now)
|
|
41
|
-
|
|
42
|
-
## update ledger (balances) with new confirmed transactions
|
|
43
|
-
@ledger = Ledger.new( @chain )
|
|
44
|
-
|
|
45
|
-
@cache.write as_json
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def sufficient_funds?( wallet, amount )
|
|
50
|
-
## (convenience) delegate for ledger
|
|
51
|
-
## todo/check: use address instead of wallet - why? why not?
|
|
52
|
-
## for now single address wallet (that is, wallet==address)
|
|
53
|
-
@ledger.sufficient_funds?( wallet, amount )
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def add_transaction( tx )
|
|
58
|
-
if tx.valid? && transaction_is_new?( tx )
|
|
59
|
-
@pending << tx
|
|
60
|
-
@cache.write as_json
|
|
61
|
-
return true
|
|
62
|
-
else
|
|
63
|
-
return false
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
##
|
|
69
|
-
# check - how to name incoming chain - chain_new, chain_candidate - why? why not?
|
|
70
|
-
# what's an intuitive name - what's gets used most often???
|
|
71
|
-
|
|
72
|
-
def resolve!( chain_new )
|
|
73
|
-
# TODO this does not protect against invalid block shapes (bogus COINBASE transactions for example)
|
|
74
|
-
|
|
75
|
-
if !chain_new.empty? && chain_new.last.valid? && chain_new.size > @chain.size
|
|
76
|
-
@chain = chain_new
|
|
77
|
-
## update ledger (balances) with new confirmed transactions
|
|
78
|
-
@ledger = Ledger.new( @chain )
|
|
79
|
-
|
|
80
|
-
## document - keep only pending transaction not yet (confirmed) in (new) blockchain ????
|
|
81
|
-
@pending.update!( @chain.transactions )
|
|
82
|
-
@cache.write as_json
|
|
83
|
-
return true
|
|
84
|
-
else
|
|
85
|
-
return false
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def as_json
|
|
92
|
-
{ chain: @chain.as_json,
|
|
93
|
-
transactions: @pending.as_json
|
|
94
|
-
}
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
private
|
|
100
|
-
|
|
101
|
-
def transaction_is_new?( tx_new )
|
|
102
|
-
## check if tx exists already in blockchain or pending tx pool
|
|
103
|
-
|
|
104
|
-
## todo: use chain.include? to check for include
|
|
105
|
-
## avoid loop and create new array for check!!!
|
|
106
|
-
(@chain.transactions + @pending.transactions).none? { |tx| tx_new.id == tx.id }
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
end ## class Bank
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
class Bank
|
|
4
|
+
attr_reader :pending, :chain, :ledger
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def initialize( address )
|
|
8
|
+
@address = address
|
|
9
|
+
|
|
10
|
+
## note: add address name for now to cache
|
|
11
|
+
## allows to start more nodes in same folder / directory
|
|
12
|
+
@cache = Cache.new( "data.#{address.downcase}.json" )
|
|
13
|
+
h = @cache.read
|
|
14
|
+
if h
|
|
15
|
+
## restore blockchain
|
|
16
|
+
@chain = Blockchain.from_json( h['chain'] )
|
|
17
|
+
## restore pending (unconfirmed) transactions pool too
|
|
18
|
+
@pending = Pool.from_json( h['transactions'] )
|
|
19
|
+
else
|
|
20
|
+
@chain = Blockchain.new
|
|
21
|
+
@chain << [Tx.new( Centralbank.config.rand_coinbase,
|
|
22
|
+
@address,
|
|
23
|
+
Centralbank.config.mining_reward )] # genesis (big bang!) starter block
|
|
24
|
+
@pending = Pool.new
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
## update ledger (balances) with confirmed transactions
|
|
28
|
+
@ledger = Ledger.new( @chain )
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def mine_block!
|
|
34
|
+
add_transaction( Tx.new( Centralbank.config.rand_coinbase,
|
|
35
|
+
@address,
|
|
36
|
+
Centralbank.config.mining_reward ))
|
|
37
|
+
|
|
38
|
+
## add mined (w/ computed/calculated hash) block
|
|
39
|
+
@chain << @pending.transactions
|
|
40
|
+
@pending = Pool.new ## clear out/ empty pool (just create a new one for now)
|
|
41
|
+
|
|
42
|
+
## update ledger (balances) with new confirmed transactions
|
|
43
|
+
@ledger = Ledger.new( @chain )
|
|
44
|
+
|
|
45
|
+
@cache.write as_json
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def sufficient_funds?( wallet, amount )
|
|
50
|
+
## (convenience) delegate for ledger
|
|
51
|
+
## todo/check: use address instead of wallet - why? why not?
|
|
52
|
+
## for now single address wallet (that is, wallet==address)
|
|
53
|
+
@ledger.sufficient_funds?( wallet, amount )
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def add_transaction( tx )
|
|
58
|
+
if tx.valid? && transaction_is_new?( tx )
|
|
59
|
+
@pending << tx
|
|
60
|
+
@cache.write as_json
|
|
61
|
+
return true
|
|
62
|
+
else
|
|
63
|
+
return false
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
# check - how to name incoming chain - chain_new, chain_candidate - why? why not?
|
|
70
|
+
# what's an intuitive name - what's gets used most often???
|
|
71
|
+
|
|
72
|
+
def resolve!( chain_new )
|
|
73
|
+
# TODO this does not protect against invalid block shapes (bogus COINBASE transactions for example)
|
|
74
|
+
|
|
75
|
+
if !chain_new.empty? && chain_new.last.valid? && chain_new.size > @chain.size
|
|
76
|
+
@chain = chain_new
|
|
77
|
+
## update ledger (balances) with new confirmed transactions
|
|
78
|
+
@ledger = Ledger.new( @chain )
|
|
79
|
+
|
|
80
|
+
## document - keep only pending transaction not yet (confirmed) in (new) blockchain ????
|
|
81
|
+
@pending.update!( @chain.transactions )
|
|
82
|
+
@cache.write as_json
|
|
83
|
+
return true
|
|
84
|
+
else
|
|
85
|
+
return false
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def as_json
|
|
92
|
+
{ chain: @chain.as_json,
|
|
93
|
+
transactions: @pending.as_json
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
def transaction_is_new?( tx_new )
|
|
102
|
+
## check if tx exists already in blockchain or pending tx pool
|
|
103
|
+
|
|
104
|
+
## todo: use chain.include? to check for include
|
|
105
|
+
## avoid loop and create new array for check!!!
|
|
106
|
+
(@chain.transactions + @pending.transactions).none? { |tx| tx_new.id == tx.id }
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end ## class Bank
|