centralbank 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f068e40d44f33359ab2e4e52a1cc4225a5f8889f
4
- data.tar.gz: 9e5e516e4ad710ca788cec1127b38ff195963a4e
3
+ metadata.gz: 2515cd5ffc9b10106967ee1a9a9debb055f903ed
4
+ data.tar.gz: 66659648d73015c121fb89fe5e9b1027efd80480
5
5
  SHA512:
6
- metadata.gz: '0810cd371d9696b64d1e03db898da57878c93f10918f4498742b71cb79e792ba032e8700450636870ba64006b02ca33b8702816c623e6c532fa9a98aa1327b98'
7
- data.tar.gz: 7a5fc1f5039caa7b62a3439cbbb47660b905145b92922e363ed9fbd3afadf5db13440096e06dfbee40e3270cb665ac8a53c7ff0d37d5989e92970bb60c26fd59
6
+ metadata.gz: eddc4d10f787ba4e3822f794f1bcf9fe2eb3fe45d01abddd9a6ec46d19d4d34d6097c7a6d93045d33b5576f8c36d6b8e9594a821a79920d8aa31b185e6792824
7
+ data.tar.gz: ac3528bc56a2e997e273696e334bfdefa6fc5bd614a6b64cae09cec5bd2cb05011502d229b155c97d50faecd61215e7ce2dc9b1eab11bbcebd34eee82021e981
data/LICENSE.md ADDED
@@ -0,0 +1,116 @@
1
+ CC0 1.0 Universal
2
+
3
+ Statement of Purpose
4
+
5
+ The laws of most jurisdictions throughout the world automatically confer
6
+ exclusive Copyright and Related Rights (defined below) upon the creator and
7
+ subsequent owner(s) (each and all, an "owner") of an original work of
8
+ authorship and/or a database (each, a "Work").
9
+
10
+ Certain owners wish to permanently relinquish those rights to a Work for the
11
+ purpose of contributing to a commons of creative, cultural and scientific
12
+ works ("Commons") that the public can reliably and without fear of later
13
+ claims of infringement build upon, modify, incorporate in other works, reuse
14
+ and redistribute as freely as possible in any form whatsoever and for any
15
+ purposes, including without limitation commercial purposes. These owners may
16
+ contribute to the Commons to promote the ideal of a free culture and the
17
+ further production of creative, cultural and scientific works, or to gain
18
+ reputation or greater distribution for their Work in part through the use and
19
+ efforts of others.
20
+
21
+ For these and/or other purposes and motivations, and without any expectation
22
+ of additional consideration or compensation, the person associating CC0 with a
23
+ Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24
+ and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25
+ and publicly distribute the Work under its terms, with knowledge of his or her
26
+ Copyright and Related Rights in the Work and the meaning and intended legal
27
+ effect of CC0 on those rights.
28
+
29
+ 1. Copyright and Related Rights. A Work made available under CC0 may be
30
+ protected by copyright and related or neighboring rights ("Copyright and
31
+ Related Rights"). Copyright and Related Rights include, but are not limited
32
+ to, the following:
33
+
34
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
35
+ and translate a Work;
36
+
37
+ ii. moral rights retained by the original author(s) and/or performer(s);
38
+
39
+ iii. publicity and privacy rights pertaining to a person's image or likeness
40
+ depicted in a Work;
41
+
42
+ iv. rights protecting against unfair competition in regards to a Work,
43
+ subject to the limitations in paragraph 4(a), below;
44
+
45
+ v. rights protecting the extraction, dissemination, use and reuse of data in
46
+ a Work;
47
+
48
+ vi. database rights (such as those arising under Directive 96/9/EC of the
49
+ European Parliament and of the Council of 11 March 1996 on the legal
50
+ protection of databases, and under any national implementation thereof,
51
+ including any amended or successor version of such directive); and
52
+
53
+ vii. other similar, equivalent or corresponding rights throughout the world
54
+ based on applicable law or treaty, and any national implementations thereof.
55
+
56
+ 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57
+ applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58
+ unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59
+ and Related Rights and associated claims and causes of action, whether now
60
+ known or unknown (including existing as well as future claims and causes of
61
+ action), in the Work (i) in all territories worldwide, (ii) for the maximum
62
+ duration provided by applicable law or treaty (including future time
63
+ extensions), (iii) in any current or future medium and for any number of
64
+ copies, and (iv) for any purpose whatsoever, including without limitation
65
+ commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66
+ the Waiver for the benefit of each member of the public at large and to the
67
+ detriment of Affirmer's heirs and successors, fully intending that such Waiver
68
+ shall not be subject to revocation, rescission, cancellation, termination, or
69
+ any other legal or equitable action to disrupt the quiet enjoyment of the Work
70
+ by the public as contemplated by Affirmer's express Statement of Purpose.
71
+
72
+ 3. Public License Fallback. Should any part of the Waiver for any reason be
73
+ judged legally invalid or ineffective under applicable law, then the Waiver
74
+ shall be preserved to the maximum extent permitted taking into account
75
+ Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76
+ is so judged Affirmer hereby grants to each affected person a royalty-free,
77
+ non transferable, non sublicensable, non exclusive, irrevocable and
78
+ unconditional license to exercise Affirmer's Copyright and Related Rights in
79
+ the Work (i) in all territories worldwide, (ii) for the maximum duration
80
+ provided by applicable law or treaty (including future time extensions), (iii)
81
+ in any current or future medium and for any number of copies, and (iv) for any
82
+ purpose whatsoever, including without limitation commercial, advertising or
83
+ promotional purposes (the "License"). The License shall be deemed effective as
84
+ of the date CC0 was applied by Affirmer to the Work. Should any part of the
85
+ License for any reason be judged legally invalid or ineffective under
86
+ applicable law, such partial invalidity or ineffectiveness shall not
87
+ invalidate the remainder of the License, and in such case Affirmer hereby
88
+ affirms that he or she will not (i) exercise any of his or her remaining
89
+ Copyright and Related Rights in the Work or (ii) assert any associated claims
90
+ and causes of action with respect to the Work, in either case contrary to
91
+ Affirmer's express Statement of Purpose.
92
+
93
+ 4. Limitations and Disclaimers.
94
+
95
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
96
+ surrendered, licensed or otherwise affected by this document.
97
+
98
+ b. Affirmer offers the Work as-is and makes no representations or warranties
99
+ of any kind concerning the Work, express, implied, statutory or otherwise,
100
+ including without limitation warranties of title, merchantability, fitness
101
+ for a particular purpose, non infringement, or the absence of latent or
102
+ other defects, accuracy, or the present or absence of errors, whether or not
103
+ discoverable, all to the greatest extent permissible under applicable law.
104
+
105
+ c. Affirmer disclaims responsibility for clearing rights of other persons
106
+ that may apply to the Work or any use thereof, including without limitation
107
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
108
+ disclaims responsibility for obtaining any necessary consents, permissions
109
+ or other rights required for any use of the Work.
110
+
111
+ d. Affirmer understands and acknowledges that Creative Commons is not a
112
+ party to this document and has no duty or obligation with respect to this
113
+ CC0 or use of the Work.
114
+
115
+ For more information, please see
116
+ <http://creativecommons.org/publicdomain/zero/1.0/>
data/Manifest.txt CHANGED
@@ -1,7 +1,9 @@
1
1
  HISTORY.md
2
+ LICENSE.md
2
3
  Manifest.txt
3
4
  README.md
4
5
  Rakefile
6
+ bin/centralbank
5
7
  lib/centralbank.rb
6
8
  lib/centralbank/bank.rb
7
9
  lib/centralbank/block.rb
@@ -9,7 +11,9 @@ lib/centralbank/blockchain.rb
9
11
  lib/centralbank/cache.rb
10
12
  lib/centralbank/ledger.rb
11
13
  lib/centralbank/node.rb
12
- lib/centralbank/public/style.css
14
+ lib/centralbank/pool.rb
15
+ lib/centralbank/service.rb
16
+ lib/centralbank/tool.rb
13
17
  lib/centralbank/transaction.rb
14
18
  lib/centralbank/version.rb
15
19
  lib/centralbank/views/_blockchain.erb
@@ -18,4 +22,5 @@ lib/centralbank/views/_peers.erb
18
22
  lib/centralbank/views/_pending_transactions.erb
19
23
  lib/centralbank/views/_wallet.erb
20
24
  lib/centralbank/views/index.erb
25
+ lib/centralbank/views/style.scss
21
26
  lib/centralbank/wallet.rb
data/README.md CHANGED
@@ -1,9 +1,67 @@
1
- # Central Bank
1
+ # centralbank library / gem and command line tool
2
2
 
3
+ 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
3
4
 
4
5
 
6
+ * home :: [github.com/openblockchains/centralbank](https://github.com/openblockchains/centralbank)
7
+ * bugs :: [github.com/openblockchains/centralbank/issues](https://github.com/openblockchains/centralbank/issues)
8
+ * gem :: [rubygems.org/gems/centralbank](https://rubygems.org/gems/centralbank)
9
+ * rdoc :: [rubydoc.info/gems/centralbank](http://rubydoc.info/gems/centralbank)
5
10
 
6
- ## Todos
7
11
 
8
- - [ ] add a Pool class (for pending transaction pool) !!!!!
9
- - [ ] add secure versions with signature e.g. SecureWallet, SecureTransaction, etc.
12
+
13
+
14
+ ## Development
15
+
16
+ For local development - clone or download (and unzip) the centralbank code repo.
17
+ Next install all dependencies using bundler with a Gemfile e.g.:
18
+
19
+ ``` ruby
20
+ # Gemfile
21
+
22
+ source "https://rubygems.org"
23
+
24
+ gem 'sinatra'
25
+ gem 'sass'
26
+ gem 'blockchain-lite'
27
+ ```
28
+
29
+ run
30
+
31
+ ```
32
+ $ bundle ## will use the Gemfile (see above)
33
+ ```
34
+
35
+ and now you're ready to run your own centralbank server node. Use the [`config.ru`](config.ru) script for rack:
36
+
37
+ ``` ruby
38
+ # config.ru
39
+
40
+ $LOAD_PATH << './lib'
41
+
42
+ require 'centralbank'
43
+
44
+ run Centralbank::Service
45
+ ```
46
+
47
+ and startup the money printing machine using rackup - the rack command line tool:
48
+
49
+ ```
50
+ $ rackup ## will use the config.ru - rackup configuration script (see above).
51
+ ```
52
+
53
+ In your browser open up the page e.g. `http://localhost:9292`. Voila!
54
+
55
+ ![](centralbank.png)
56
+
57
+
58
+ Happy mining!
59
+
60
+
61
+
62
+ ## License
63
+
64
+ ![](https://publicdomainworks.github.io/buttons/zero88x31.png)
65
+
66
+ The `centralbank` scripts are dedicated to the public domain.
67
+ Use it as you please with no restrictions whatsoever.
data/Rakefile CHANGED
@@ -18,7 +18,9 @@ Hoe.spec 'centralbank' do
18
18
  self.history_file = 'History.md'
19
19
 
20
20
  self.extra_deps = [
21
- ['sinatra', '>=2.0']
21
+ ['sinatra', '>=2.0'],
22
+ ['sass'], ## used for css style preprocessing (scss)
23
+ ['blockchain-lite', '>=1.3.1'],
22
24
  ]
23
25
 
24
26
  self.licenses = ['Public Domain']
data/bin/centralbank ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ###################
4
+ # == DEV TIPS:
5
+ #
6
+ # For local testing run like:
7
+ #
8
+ # ruby -Ilib bin/centralbank
9
+ #
10
+ # Set the executable bit in Linux. Example:
11
+ #
12
+ # % chmod a+x bin/centralbank
13
+ #
14
+
15
+ require 'centralbank'
16
+
17
+ Centralbank.main
data/lib/centralbank.rb CHANGED
@@ -6,14 +6,14 @@ require 'digest'
6
6
  require 'net/http'
7
7
  require 'set'
8
8
  require 'pp'
9
-
10
- ## require 'blockchain-lite'
11
- ## Block = BlockchainLite::Basic::Block
9
+ require 'optparse' ## note: used for command line tool (see Tool in tool.rb)
12
10
 
13
11
 
14
12
  ### 3rd party gems
15
- require 'sinatra/base' # note: use "modular" sinatra app / service
13
+ require 'sinatra/base' # note: use "modular" sinatra app / service
16
14
 
15
+ require 'merkletree'
16
+ require 'blockchain-lite/proof_of_work/block' # note: use proof-of-work block only (for now)
17
17
 
18
18
 
19
19
  ### our own code
@@ -22,105 +22,64 @@ require 'centralbank/block'
22
22
  require 'centralbank/cache'
23
23
  require 'centralbank/transaction'
24
24
  require 'centralbank/blockchain'
25
+ require 'centralbank/pool'
25
26
  require 'centralbank/bank'
26
27
  require 'centralbank/ledger'
27
28
  require 'centralbank/wallet'
28
29
 
29
30
  require 'centralbank/node'
31
+ require 'centralbank/service'
30
32
 
33
+ require 'centralbank/tool' ## add (optional) command line tool
31
34
 
32
35
 
33
36
 
34
- module Centralbank
35
-
36
- class Service < Sinatra::Base
37
-
38
- def self.banner
39
- "centralbank/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] on Sinatra/#{Sinatra::VERSION} (#{ENV['RACK_ENV']})"
40
- end
41
-
42
-
43
- ## - for now hard-code address e.g. Sepp
44
- NODE = Node.new( address: 'Sepp' )
45
-
46
37
 
47
- PUBLIC_FOLDER = "#{Centralbank.root}/lib/centralbank/public"
48
- VIEWS_FOLDER = "#{Centralbank.root}/lib/centralbank/views"
49
38
 
50
- puts "[centralbank] boot - setting public folder to: #{PUBLIC_FOLDER}"
51
- puts "[centralbank] boot - setting views folder to: #{VIEWS_FOLDER}"
39
+ module Centralbank
52
40
 
53
- set :public_folder, PUBLIC_FOLDER # set up the static dir (with images/js/css inside)
54
- set :views, VIEWS_FOLDER # set up the views dir
55
41
 
56
- set :static, true # set up static file routing -- check - still needed?
42
+ class Configuration
43
+ ## user/node settings
44
+ attr_accessor :address ## single wallet address (for now "clear" name e.g.Sepp, Franz, etc.)
57
45
 
46
+ WALLET_ADDRESSES = %w[Alice Bob Max Franz Maria Ferdl Lisi Adam Eva]
58
47
 
59
- set connections: []
48
+ ## system/blockchain settings
49
+ attr_accessor :coinbase
50
+ attr_accessor :mining_reward
60
51
 
61
52
 
53
+ def initialize
54
+ ## try default setup via ENV variables
55
+ ## pick "random" address if nil (none passed in)
56
+ @address = ENV[ 'CENTRALBANK_NAME'] || WALLET_ADDRESSES[rand( WALLET_ADDRESSES.size )]
62
57
 
63
- get '/' do
64
- @node = NODE
65
- erb :index
66
- end
58
+ @coinbase = 'COINBASE' ## use a different name - why? why not?
59
+ @mining_reward = 5
60
+ end
61
+ end # class Configuration
67
62
 
68
- post '/send' do
69
- NODE.on_send( params[:to], params[:amount].to_i )
70
- settings.connections.each { |out| out << "data: added transaction\n\n" }
71
- redirect '/'
72
- end
73
63
 
64
+ ## lets you use
65
+ ## Centralbank.configure do |config|
66
+ ## config.address = 'Sepp'
67
+ ## end
74
68
 
75
- post '/transactions' do
76
- if NODE.on_add_transaction(
77
- params[:from],
78
- params[:to],
79
- params[:amount].to_i,
80
- params[:id]
81
- )
82
- settings.connections.each { |out| out << "data: added transaction\n\n" }
69
+ def self.configure
70
+ yield( config )
83
71
  end
84
- redirect '/'
85
- end
86
-
87
- post '/mine' do
88
- NODE.on_mine!
89
- redirect '/'
90
- end
91
-
92
- post '/peers' do
93
- NODE.on_add_peer( params[:host], params[:port].to_i )
94
- redirect '/'
95
- end
96
-
97
- post '/peers/:index/delete' do
98
- NODE.on_delete_peer( params[:index].to_i )
99
- redirect '/'
100
- end
101
72
 
102
-
103
-
104
- post '/resolve' do
105
- data = JSON.parse(request.body.read)
106
- if data['chain'] && NODE.on_resolve( data['chain'] )
107
- status 202 ### 202 Accepted; see httpstatuses.com/202
108
- settings.connections.each { |out| out << "data: resolved\n\n" }
109
- else
110
- status 200 ### 200 OK
73
+ def self.config
74
+ @config ||= Configuration.new
111
75
  end
112
- end
113
76
 
114
77
 
115
- get '/events', provides: 'text/event-stream' do
116
- stream :keep_open do |out|
117
- settings.connections << out
118
- out.callback { settings.connections.delete(out) }
78
+ ## add command line binary (tool) e.g. $ try centralbank -h
79
+ def self.main
80
+ Tool.new.run(ARGV)
119
81
  end
120
- end
121
-
122
82
 
123
- end # class Service
124
83
  end # module Centralbank
125
84
 
126
85
 
@@ -1,28 +1,27 @@
1
1
 
2
2
 
3
-
4
-
5
3
  class Bank
6
4
  attr_reader :pending, :chain, :ledger
7
5
 
8
- COINBASE = "COINBASE"
9
- MINING_REWARD = 5
10
-
11
6
 
12
7
  def initialize( address )
13
8
  @address = address
14
9
 
15
- @cache = Cache.new( 'data.json' )
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" )
16
13
  h = @cache.read
17
14
  if h
18
15
  ## restore blockchain
19
16
  @chain = Blockchain.from_json( h['chain'] )
20
- ## restore pending transactions too
21
- @pending = h['transactions'].map { |h_tx| Tx.from_h( h_tx ) }
17
+ ## restore pending (unconfirmed) transactions pool too
18
+ @pending = Pool.from_json( h['transactions'] )
22
19
  else
23
20
  @chain = Blockchain.new
24
- @chain << [Tx.new( COINBASE, @address, MINING_REWARD )] # genesis (big bang!) starter block
25
- @pending = []
21
+ @chain << [Tx.new( Centralbank.config.coinbase,
22
+ @address,
23
+ Centralbank.config.mining_reward )] # genesis (big bang!) starter block
24
+ @pending = Pool.new
26
25
  end
27
26
 
28
27
  ## update ledger (balances) with confirmed transactions
@@ -32,11 +31,13 @@ class Bank
32
31
 
33
32
 
34
33
  def mine_block!
35
- add_transaction( Tx.new( COINBASE, @address, MINING_REWARD ))
34
+ add_transaction( Tx.new( Centralbank.config.coinbase,
35
+ @address,
36
+ Centralbank.config.mining_reward ))
36
37
 
37
38
  ## add mined (w/ computed/calculated hash) block
38
- @chain << @pending
39
- @pending = []
39
+ @chain << @pending.transactions
40
+ @pending = Pool.new ## clear out/ empty pool (just create a new one for now)
40
41
 
41
42
  ## update ledger (balances) with new confirmed transactions
42
43
  @ledger = Ledger.new( @chain )
@@ -76,13 +77,8 @@ class Bank
76
77
  ## update ledger (balances) with new confirmed transactions
77
78
  @ledger = Ledger.new( @chain )
78
79
 
79
-
80
- _transactions = @chain.transactions ## use a copy for reference (optimization) in inner loop
81
- ## todo: cleanup ??? -- use tx2 for t ???
82
- ## document - keep only pending transaction not yet in blockchain ????
83
- @pending = @pending.select do |tx|
84
- _transactions.none? { |tx_confirmed| tx_confirmed.id == tx.id }
85
- end
80
+ ## document - keep only pending transaction not yet (confirmed) in (new) blockchain ????
81
+ @pending.update!( @chain.transactions )
86
82
  @cache.write as_json
87
83
  return true
88
84
  else
@@ -94,7 +90,7 @@ class Bank
94
90
 
95
91
  def as_json
96
92
  { chain: @chain.as_json,
97
- transactions: @pending.map { |tx| tx.to_h }
93
+ transactions: @pending.as_json
98
94
  }
99
95
  end
100
96
 
@@ -107,7 +103,7 @@ private
107
103
 
108
104
  ## todo: use chain.include? to check for include
109
105
  ## avoid loop and create new array for check!!!
110
- (@chain.transactions + @pending).none? { |tx| tx_new.id == tx.id }
106
+ (@chain.transactions + @pending.transactions).none? { |tx| tx_new.id == tx.id }
111
107
  end
112
108
 
113
109
  end ## class Bank
@@ -1,53 +1,41 @@
1
1
 
2
- ##################
3
- # todo: add proof-of-work (nounce calculation) !!!!
4
- #
5
-
6
- class Block
7
-
8
- attr_reader :index, :timestamp, :transactions, :previous_hash, :hash
9
-
10
- def initialize( index, transactions, previous_hash )
11
- @index = index
12
- @timestamp = Time.now.utc ## note: use coordinated universal time (utc)
13
- @transactions = transactions
14
- @previous_hash = previous_hash
15
- @hash = calc_hash
16
- end
17
-
18
- def calc_hash
19
- sha = Digest::SHA256.new
20
- sha.update( @index.to_s + @time.to_s + @transactions.to_s + @previous_hash )
21
- sha.hexdigest
22
- end
23
2
 
3
+ Block = BlockchainLite::ProofOfWork::Block
24
4
 
25
- def self.first( transactions ) # create genesis (big bang! first) block
26
- ## uses index zero (0) and arbitrary previous_hash ('0')
27
- self.new( 0, transactions, '0' )
28
- end
5
+ ## see https://github.com/openblockchains/blockchain.lite.rb/blob/master/lib/blockchain-lite/proof_of_work/block.rb
29
6
 
30
- def self.next( previous, transactions )
31
- self.new( previous.index+1, transactions, previous.hash )
32
- end
7
+ ######
8
+ ## add more methods
33
9
 
10
+ class Block
34
11
 
35
12
 
36
13
  def to_h
37
- { index: @index,
38
- timestamp: @timestamp,
39
- transactions: @transactions.map { |tx| tx.to_h },
40
- previous_hash: @previous_hash }
14
+ { index: @index,
15
+ timestamp: @timestamp,
16
+ nonce: @nonce,
17
+ transactions: @transactions.map { |tx| tx.to_h },
18
+ transactions_hash: @transactions_hash,
19
+ previous_hash: @previous_hash,
20
+ hash: @hash }
41
21
  end
42
22
 
43
23
  def self.from_h( h )
44
24
  transactions = h['transactions'].map { |h_tx| Tx.from_h( h_tx ) }
25
+
26
+ ## todo: use hash and transactions_hash to check integrity of block - why? why not?
27
+
28
+ ## parse iso8601 format e.g 2017-10-05T22:26:12-04:00
29
+ timestamp = Time.parse( h['timestamp'] )
30
+
45
31
  self.new( h['index'],
46
- ## h['timestamp'], -- fix!!!: change use keyword params (make timestamp optional)
47
32
  transactions,
48
- h['previous_hash'] )
33
+ h['previous_hash'],
34
+ timestamp: timestamp,
35
+ nonce: h['nonce'].to_i )
49
36
  end
50
37
 
38
+
51
39
  def valid?
52
40
  true ## for now always valid
53
41
  end
@@ -3,7 +3,7 @@
3
3
 
4
4
  class Blockchain
5
5
  extend Forwardable
6
- def_delegators :@chain, :[], :size, :each, :empty?, :last
6
+ def_delegators :@chain, :[], :size, :each, :empty?, :any?, :last
7
7
 
8
8
 
9
9
  def initialize( chain=[] )
@@ -10,7 +10,7 @@ class Ledger
10
10
  end
11
11
 
12
12
  def sufficient_funds?( wallet, amount )
13
- return true if wallet == Bank::COINBASE ### use Config::COINBASE why? why not ???
13
+ return true if wallet == Centralbank.config.coinbase
14
14
  @wallets.has_key?( wallet ) && @wallets[wallet] - amount >= 0
15
15
  end
16
16
 
@@ -20,7 +20,7 @@ private
20
20
  def apply_transactions( transactions )
21
21
  transactions.each do |tx|
22
22
  if sufficient_funds?(tx.from, tx.amount)
23
- @wallets[tx.from] -= tx.amount unless tx.from == Bank::COINBASE ### use Config::COINBASE why? why not ???
23
+ @wallets[tx.from] -= tx.amount unless tx.from == Centralbank.config.coinbase
24
24
  @wallets[tx.to] ||= 0
25
25
  @wallets[tx.to] += tx.amount
26
26
  end
@@ -3,13 +3,7 @@
3
3
  class Node
4
4
  attr_reader :id, :peers, :wallet, :bank
5
5
 
6
-
7
- WALLET_ADDRESSES = %w[Sepp Franz Sissi Maria Eva Ferdl Max Adam]
8
-
9
- def initialize( address: nil )
10
- ## pick "random" address if nil (none passed in)
11
- address ||= WALLET_ADDRESSES[rand( WALLET_ADDRESSES.size )]
12
-
6
+ def initialize( address: )
13
7
  @id = SecureRandom.uuid
14
8
  @peers = []
15
9
  @wallet = Wallet.new( address )
@@ -0,0 +1,42 @@
1
+ ####################################
2
+ # pending (unconfirmed) transactions (mem) pool
3
+
4
+ class Pool
5
+ extend Forwardable
6
+ def_delegators :@transactions, :[], :size, :each, :empty?, :any?
7
+
8
+
9
+ def initialize( transactions=[] )
10
+ @transactions = transactions
11
+ end
12
+
13
+ def transactions() @transactions; end
14
+
15
+ def <<( tx )
16
+ @transactions << tx
17
+ end
18
+
19
+
20
+ def update!( txns_confirmed )
21
+ ## find a better name?
22
+ ## remove confirmed transactions from pool
23
+
24
+ ## document - keep only pending transaction not yet (confirmed) in blockchain ????
25
+ @transactions = @transactions.select do |tx_unconfirmed|
26
+ txns_confirmed.none? { |tx_confirmed| tx_confirmed.id == tx_unconfirmed.id }
27
+ end
28
+ end
29
+
30
+
31
+
32
+ def as_json
33
+ @transactions.map { |tx| tx.to_h }
34
+ end
35
+
36
+ def self.from_json( data )
37
+ ## note: assumes data is an array of block records/objects in json
38
+ transactions = data.map { |h| Tx.from_h( h ) }
39
+ self.new( transactions )
40
+ end
41
+
42
+ end # class Pool
@@ -0,0 +1,114 @@
1
+ # encoding: utf-8
2
+
3
+ module Centralbank
4
+
5
+ class Service < Sinatra::Base
6
+
7
+ def self.banner
8
+ "centralbank/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] on Sinatra/#{Sinatra::VERSION} (#{ENV['RACK_ENV']})"
9
+ end
10
+
11
+
12
+ PUBLIC_FOLDER = "#{Centralbank.root}/lib/centralbank/public"
13
+ VIEWS_FOLDER = "#{Centralbank.root}/lib/centralbank/views"
14
+
15
+ puts "[centralbank] boot - setting public folder to: #{PUBLIC_FOLDER}"
16
+ puts "[centralbank] boot - setting views folder to: #{VIEWS_FOLDER}"
17
+
18
+ set :public_folder, PUBLIC_FOLDER # set up the static dir (with images/js/css inside)
19
+ set :views, VIEWS_FOLDER # set up the views dir
20
+
21
+ set :static, true # set up static file routing -- check - still needed?
22
+
23
+
24
+ set connections: []
25
+
26
+
27
+ #########
28
+ ## return network node (built and configured on first use)
29
+ ## fix: do NOT use @@ - use a class level method or something
30
+ def node
31
+ if defined?( @@node )
32
+ @@node
33
+ else
34
+ puts "[debug] centralbank - build (network) node (address: #{Centralbank.config.address})"
35
+ @@node = Node.new( address: Centralbank.config.address )
36
+ @@node
37
+ end
38
+ ####
39
+ ## check why this is a syntax error:
40
+ ## @node ||= do
41
+ ## puts "[debug] centralbank - build (network) node (address: #{Centralbank.config.address})"
42
+ ## @node = Node.new( address: Centralbank.config.address )
43
+ ## end
44
+ end
45
+
46
+ get '/style.css' do
47
+ scss :style ## note: converts (pre-processes) style.scss to style.css
48
+ end
49
+
50
+
51
+ get '/' do
52
+ @node = node ## todo: pass along node as hash varialbe / assigns to erb
53
+ erb :index
54
+ end
55
+
56
+
57
+ post '/send' do
58
+ node.on_send( params[:to], params[:amount].to_i )
59
+ settings.connections.each { |out| out << "data: added transaction\n\n" }
60
+ redirect '/'
61
+ end
62
+
63
+
64
+ post '/transactions' do
65
+ if node.on_add_transaction(
66
+ params[:from],
67
+ params[:to],
68
+ params[:amount].to_i,
69
+ params[:id]
70
+ )
71
+ settings.connections.each { |out| out << "data: added transaction\n\n" }
72
+ end
73
+ redirect '/'
74
+ end
75
+
76
+ post '/mine' do
77
+ node.on_mine!
78
+ redirect '/'
79
+ end
80
+
81
+ post '/peers' do
82
+ node.on_add_peer( params[:host], params[:port].to_i )
83
+ redirect '/'
84
+ end
85
+
86
+ post '/peers/:index/delete' do
87
+ node.on_delete_peer( params[:index].to_i )
88
+ redirect '/'
89
+ end
90
+
91
+
92
+
93
+ post '/resolve' do
94
+ data = JSON.parse(request.body.read)
95
+ if data['chain'] && node.on_resolve( data['chain'] )
96
+ status 202 ### 202 Accepted; see httpstatuses.com/202
97
+ settings.connections.each { |out| out << "data: resolved\n\n" }
98
+ else
99
+ status 200 ### 200 OK
100
+ end
101
+ end
102
+
103
+
104
+ get '/events', provides: 'text/event-stream' do
105
+ stream :keep_open do |out|
106
+ settings.connections << out
107
+ out.callback { settings.connections.delete(out) }
108
+ end
109
+ end
110
+
111
+
112
+ end # class Service
113
+
114
+ end # module Centralbank
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+
4
+ module Centralbank
5
+
6
+ class Tool
7
+
8
+ def run( args )
9
+ opts = {}
10
+
11
+ parser = OptionParser.new do |cmd|
12
+ cmd.banner = "Usage: centralbank [options]"
13
+
14
+ cmd.separator ""
15
+ cmd.separator " Wallet options:"
16
+
17
+ cmd.on("-n", "--name=NAME", "Address name (default: Alice)") do |name|
18
+ ## use -a or --adr or --address as option flag - why? why not?
19
+ ## note: default now picks a random address from WALLET_ADDRESSES
20
+ opts[:address] = name
21
+ end
22
+
23
+
24
+ cmd.separator ""
25
+ cmd.separator " Server (node) options:"
26
+
27
+ cmd.on("-o", "--host HOST", "listen on HOST (default: 0.0.0.0)") do |host|
28
+ opts[:Host] = host ## note: rack server handler expects :Host
29
+ end
30
+
31
+ cmd.on("-p", "--port PORT", "use PORT (default: 4567)") do |port|
32
+ opts[:Port] = port ## note: rack server handler expects :Post
33
+ end
34
+
35
+ cmd.on("-h", "--help", "Prints this help") do
36
+ puts cmd
37
+ exit
38
+ end
39
+ end
40
+
41
+ parser.parse!( args )
42
+ pp opts
43
+
44
+
45
+ ###################
46
+ ## startup server (via rack interface/handler)
47
+
48
+ app_class = Service ## use app = Service.new -- why? why not?
49
+ host = opts[:Host] || '0.0.0.0'
50
+ port = opts[:Port] || '4567'
51
+
52
+ Centralbank.configure do |config|
53
+ config.address = opts[:address] || 'Alice'
54
+ end
55
+
56
+ Rack::Handler::WEBrick.run( app_class, Host: host, Port: port ) do |server|
57
+ ## todo: add traps here - why, why not??
58
+ end
59
+
60
+
61
+ end ## method run
62
+
63
+
64
+ end ## class Tool
65
+
66
+ end ## module Centralbank
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Centralbank
4
4
 
5
- VERSION = '0.1.0'
5
+ VERSION = '0.2.0'
6
6
 
7
7
  def self.root
8
8
  "#{File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )}"
@@ -1,25 +1,30 @@
1
+
1
2
  body {
2
- background: #fff;
3
- font-family: 'menlo', monospace;
4
- color: #2B2D2F;
5
3
  padding: 0;
6
4
  margin: 0;
7
- font-size: 14px;
8
5
  min-width: 960px;
6
+
7
+ font-family: 'menlo', monospace;
8
+ font-size: 14px;
9
+
10
+ background: #fff;
11
+ color: #2B2D2F;
9
12
  }
10
13
 
14
+
11
15
  .columns {
12
16
  display: flex;
13
- }
14
17
 
15
- .left {
16
- width: 66%;
17
- }
18
+ .left {
19
+ width: 66%;
20
+ }
18
21
 
19
- .right {
20
- width: 34%;
22
+ .right {
23
+ width: 34%;
24
+ }
21
25
  }
22
26
 
27
+
23
28
  h1 {
24
29
  font-size: 24px;
25
30
  font-weight: normal;
@@ -27,6 +32,7 @@ h1 {
27
32
  margin-bottom: 20px;
28
33
  }
29
34
 
35
+
30
36
  h2 {
31
37
  font-size: 16px;
32
38
  }
@@ -55,17 +61,18 @@ input[type=text] {
55
61
  table {
56
62
  border-spacing: 0;
57
63
  border-collapse: collapse;
58
- }
59
64
 
60
- th {
61
- text-align: left;
62
- }
65
+ th {
66
+ text-align: left;
67
+ }
63
68
 
64
- td {
65
- vertical-align: top;
66
- padding: 5px 15px 5px 0;
69
+ td {
70
+ vertical-align: top;
71
+ padding: 5px 15px 5px 0;
72
+ }
67
73
  }
68
74
 
75
+
69
76
  ul {
70
77
  list-style: none;
71
78
  padding: 0;
@@ -87,77 +94,79 @@ input[type=submit].small {
87
94
  padding: 4px 10px;
88
95
  }
89
96
 
90
- .wallet,
91
- .pending-transactions,
92
- .peers,
93
- .ledger,
94
- .blockchain {
95
- padding: 15px;
96
- }
97
+
97
98
 
98
99
  .wallet {
100
+ padding: 15px;
99
101
  background: #7FDBFF;
100
- }
101
102
 
102
- .wallet h2 {
103
- margin-bottom: 0;
104
- }
103
+ h2 {
104
+ margin-bottom: 0;
105
+ }
105
106
 
106
- .balance {
107
- font-size: 30px;
107
+ .balance {
108
+ font-size: 30px;
109
+ }
108
110
  }
109
111
 
112
+
110
113
  .pending-transactions {
114
+ padding: 15px;
111
115
  background: #A3E6FF;
112
116
  }
113
117
 
114
118
  .peers {
119
+ padding: 15px;
115
120
  background: #C6EFFF;
116
- }
117
121
 
118
- .peers li form {
119
- display: inline;
122
+ li form {
123
+ display: inline;
124
+ }
125
+
126
+ li {
127
+ padding: 5px 0px;
128
+ }
120
129
  }
121
130
 
131
+
122
132
  .ledger {
133
+ padding: 15px;
123
134
  background: #E3F7FF;
124
135
  }
125
136
 
137
+
126
138
  .blockchain {
139
+ padding: 15px;
127
140
  position: relative;
128
141
  background: #001F3F;
129
142
  color: #fff;
130
- }
131
-
132
- .blockchain form {
133
- position: absolute;
134
- top: 30px;
135
- right: 15px;
136
- }
137
-
138
- .blocks {
139
- border: 1px solid #597898;
140
- border-bottom: 0;
141
- }
142
-
143
- .block {
144
- margin: 0;
145
- border-bottom: 2px dashed #597898;
146
- padding: 10px;
147
- }
148
-
149
- .block .header {
150
- text-align: center;
151
- padding: 0 8px 8px 8px;
152
- color: #597898;
153
- border-bottom: 1px solid #354c63;
154
- margin-bottom: 10px;
155
- }
156
-
157
- .block .id {
158
- color: #597898;
159
- }
160
143
 
161
- .peers li {
162
- padding: 5px 0px;
144
+ form {
145
+ position: absolute;
146
+ top: 30px;
147
+ right: 15px;
148
+ }
149
+
150
+ .blocks {
151
+ border: 1px solid #597898;
152
+ border-bottom: 0;
153
+
154
+ .block {
155
+ margin: 0;
156
+ border-bottom: 2px dashed #597898;
157
+ padding: 10px;
158
+
159
+ .header {
160
+ text-align: center;
161
+ padding: 0 8px 8px 8px;
162
+ color: #597898;
163
+ border-bottom: 1px solid #354c63;
164
+ margin-bottom: 10px;
165
+ }
166
+
167
+ .id {
168
+ color: #597898;
169
+ }
170
+ }
171
+ }
163
172
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: centralbank
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-14 00:00:00.000000000 Z
11
+ date: 2017-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sass
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: blockchain-lite
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 1.3.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3.1
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: rdoc
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -56,17 +84,21 @@ description: centralbank - print your own money / cryptocurrency; run your own f
56
84
  central bank nodes on the blockchain peer-to-peer over HTTP; revolutionize the world
57
85
  one block at a time
58
86
  email: ruby-talk@ruby-lang.org
59
- executables: []
87
+ executables:
88
+ - centralbank
60
89
  extensions: []
61
90
  extra_rdoc_files:
62
91
  - HISTORY.md
92
+ - LICENSE.md
63
93
  - Manifest.txt
64
94
  - README.md
65
95
  files:
66
96
  - HISTORY.md
97
+ - LICENSE.md
67
98
  - Manifest.txt
68
99
  - README.md
69
100
  - Rakefile
101
+ - bin/centralbank
70
102
  - lib/centralbank.rb
71
103
  - lib/centralbank/bank.rb
72
104
  - lib/centralbank/block.rb
@@ -74,7 +106,9 @@ files:
74
106
  - lib/centralbank/cache.rb
75
107
  - lib/centralbank/ledger.rb
76
108
  - lib/centralbank/node.rb
77
- - lib/centralbank/public/style.css
109
+ - lib/centralbank/pool.rb
110
+ - lib/centralbank/service.rb
111
+ - lib/centralbank/tool.rb
78
112
  - lib/centralbank/transaction.rb
79
113
  - lib/centralbank/version.rb
80
114
  - lib/centralbank/views/_blockchain.erb
@@ -83,6 +117,7 @@ files:
83
117
  - lib/centralbank/views/_pending_transactions.erb
84
118
  - lib/centralbank/views/_wallet.erb
85
119
  - lib/centralbank/views/index.erb
120
+ - lib/centralbank/views/style.scss
86
121
  - lib/centralbank/wallet.rb
87
122
  homepage: https://github.com/openblockchains/centralbank
88
123
  licenses: