centralbank 0.1.0 → 0.2.0

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
  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: