blockchain-lite 1.1.0 → 1.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: e7543889414d4d92f12f6f5bfe9d708ba12c0093
4
- data.tar.gz: 96017ba92283640a77ed3be91d52721f1e245791
3
+ metadata.gz: 7d943d2cc505e7e01dbaf6fb364ca317d55d9563
4
+ data.tar.gz: 4ab4b023a57d9ef9794e6024035c6cf6f718afaa
5
5
  SHA512:
6
- metadata.gz: 9648bcb18e39173799709aef395c346f63ff4fe6fdff824199cc0934b3b2ade710e5ef6e11e1a802d7d435cdb2ee3d905bc4bf28efbcafe64e94c3b154198d10
7
- data.tar.gz: 9b0ca66ac0656b65bc3179387ba7b9818313f94ec7e6d7f25b6ac2cb54ed57a492be7a2a37a13a813a7c6ca9550b7e50c22e3bb0268d8a4c2284d62847079b0d
6
+ metadata.gz: 4d10c42c537839b325d0ab9ebc59bd86238e985f9c549f5119b1b055bd5bf9d70a949ed51dd704082f07974408d40eb887fad1302148819d4fc6f9d63621de76
7
+ data.tar.gz: 612428a641e7e40ffab34c1c33f30a5b0e224e441479c68b551da1581c8e845f31d29624967a9c7915afce4ed6ce6f0aa421ae71f8a67924d37ea23349d55f9b
data/README.md CHANGED
@@ -10,10 +10,10 @@ blockchain-lite library / gem - build your own blockchain with crypto hashes - r
10
10
 
11
11
  ## What's a Blockchain?
12
12
 
13
- > A blockchain is a distributed database -
13
+ > A blockchain is a distributed database with
14
14
  > a list (that is, chain) of records (that is, blocks)
15
15
  > linked and secured by digital fingerprints
16
- > (that is, hashes also known as (one-way) crypto(graphic) hash digest checksums).
16
+ > (that is, crypto hashes).
17
17
 
18
18
  See the [Awesome Blockchains](https://github.com/openblockchains/awesome-blockchains) page for more.
19
19
 
@@ -28,45 +28,51 @@ require 'blockchain-lite'
28
28
 
29
29
  b0 = Block.first( 'Genesis' )
30
30
  b1 = Block.next( b0, 'Transaction Data...' )
31
- b2 = Block.next( b1, 'Transaction Data......' )
32
- b3 = Block.next( b2, 'More Transaction Data...' )
31
+ b2 = Block.next( b1, 'Transaction Data...' )
32
+ b3 = Block.next( b2, 'Transaction Data...' )
33
33
 
34
34
  blockchain = [b0, b1, b2, b3]
35
35
 
36
36
  pp blockchain
37
+ ```
38
+
39
+ will pretty print (pp) something like:
37
40
 
38
- ######
39
- # will pretty print (pp) something like:
40
- #
41
- # [#<Block:0x1eed2a0
42
- # @index = 0,
43
- # @timestamp = 2017-09-15 20:52:38,
44
- # @data = "Genesis",
45
- # @previous_hash = "0",
46
- # @hash ="edbd4e11e69bc399a9ccd8faaea44fb27410fe8e3023bb9462450a0a9c4caa1b">,
47
- # #<Block:0x1eec9a0
48
- # @index = 1,
49
- # @timestamp = 2017-09-15 20:52:38,
50
- # @data = "Transaction Data...",
51
- # @hash = "eb8ecbf6d5870763ae246e37539d82e37052cb32f88bb8c59971f9978e437743",
52
- # @previous_hash = "edbd4e11e69bc399a9ccd8faaea44fb27410fe8e3023bb9462450a0a9c4caa1b">,
53
- # #<Block:0x1eec838
54
- # @index = 2,
55
- # @timestamp = 2017-09-15 20:52:38,
56
- # @data = "Transaction Data......",
57
- # @hash = "be50017ee4bbcb33844b3dc2b7c4e476d46569b5df5762d14ceba9355f0a85f4",
58
- # @previous_hash = "eb8ecbf6d5870763ae246e37539d82e37052cb32f88bb8c59971f9978e437743">,
59
- # #<Block:0x1eec6d0
60
- # @index = 3,
61
- # @timestamp = 2017-09-15 20:52:38
62
- # @data = "More Transaction Data...",
63
- # @hash = "5ee2981606328abfe0c3b1171440f0df746c1e1f8b3b56c351727f7da7ae5d8d",
64
- # @previous_hash = "be50017ee4bbcb33844b3dc2b7c4e476d46569b5df5762d14ceba9355f0a85f4">]
41
+ ```
42
+ [#<Block:0x1eed2a0
43
+ @index = 0,
44
+ @timestamp = 2017-09-15 20:52:38,
45
+ @transactions_count = 1,
46
+ @transactions = ["Genesis"],
47
+ @previous_hash = "0",
48
+ @hash = "edbd4e11e69bc399a9ccd8faaea44fb27410fe8e3023bb9462450a0a9c4caa1b">,
49
+ #<Block:0x1eec9a0
50
+ @index = 1,
51
+ @timestamp = 2017-09-15 20:52:38,
52
+ @transactions_count = 1,
53
+ @transactions = ["Transaction Data..."],
54
+ @hash = "eb8ecbf6d5870763ae246e37539d82e37052cb32f88bb8c59971f9978e437743",
55
+ @previous_hash = "edbd4e11e69bc399a9ccd8faaea44fb27410fe8e3023bb9462450a0a9c4caa1b">,
56
+ #<Block:0x1eec838
57
+ @index = 2,
58
+ @timestamp = 2017-09-15 20:52:38,
59
+ @transactions_count = 1,
60
+ @transactions = ["Transaction Data..."],
61
+ @hash = "be50017ee4bbcb33844b3dc2b7c4e476d46569b5df5762d14ceba9355f0a85f4",
62
+ @previous_hash = "eb8ecbf6d5870763ae246e37539d82e37052cb32f88bb8c59971f9978e437743">,
63
+ #<Block:0x1eec6d0
64
+ @index = 3,
65
+ @timestamp = 2017-09-15 20:52:38
66
+ @transactions_count = 1,
67
+ @transactions = ["Transaction Data..."],
68
+ @hash = "5ee2981606328abfe0c3b1171440f0df746c1e1f8b3b56c351727f7da7ae5d8d",
69
+ @previous_hash = "be50017ee4bbcb33844b3dc2b7c4e476d46569b5df5762d14ceba9355f0a85f4">]
65
70
  ```
66
71
 
72
+
67
73
  ### Blocks
68
74
 
69
- [Basic](#basic)
75
+ [Basic](#basic)
70
76
  [Proof-of-Work](#proof-of-work)
71
77
 
72
78
  Supported block types / classes for now include:
@@ -78,21 +84,27 @@ class Block
78
84
 
79
85
  attr_reader :index
80
86
  attr_reader :timestamp
81
- attr_reader :data
87
+ attr_reader :transactions_count
88
+ attr_reader :transactions
82
89
  attr_reader :previous_hash
83
90
  attr_reader :hash
84
91
 
85
- def initialize(index, data, previous_hash)
86
- @index = index
87
- @timestamp = Time.now.utc ## note: use coordinated universal time (utc)
88
- @data = data
89
- @previous_hash = previous_hash
90
- @hash = calc_hash
92
+ def initialize(index, transactions, previous_hash)
93
+ @index = index
94
+ @timestamp = Time.now.utc ## note: use coordinated universal time (utc)
95
+ @transactions = transactions
96
+ @transactions_count = transactions.size
97
+ @previous_hash = previous_hash
98
+ @hash = calc_hash
91
99
  end
92
100
 
93
101
  def calc_hash
94
102
  sha = Digest::SHA256.new
95
- sha.update( @index.to_s + @timestamp.to_s + @data + @previous_hash )
103
+ sha.update( @index.to_s +
104
+ @timestamp.to_s +
105
+ @transactions.to_s +
106
+ @transactions_count.to_s +
107
+ @previous_hash )
96
108
  sha.hexdigest
97
109
  end
98
110
  ...
@@ -109,22 +121,29 @@ class Block
109
121
 
110
122
  attr_reader :index
111
123
  attr_reader :timestamp
112
- attr_reader :data
124
+ attr_reader :transactions_count
125
+ attr_reader :transactions
113
126
  attr_reader :previous_hash
114
127
  attr_reader :nonce ## proof of work if hash starts with leading zeros (00)
115
128
  attr_reader :hash
116
129
 
117
- def initialize(index, data, previous_hash)
118
- @index = index
119
- @timestamp = Time.now.utc ## note: use coordinated universal time (utc)
120
- @data = data
121
- @previous_hash = previous_hash
122
- @nonce, @hash = compute_hash_with_proof_of_work
130
+ def initialize(index, transactions, previous_hash)
131
+ @index = index
132
+ @timestamp = Time.now.utc ## note: use coordinated universal time (utc)
133
+ @transactions = transactions
134
+ @transactions_count = transactions.size
135
+ @previous_hash = previous_hash
136
+ @nonce, @hash = compute_hash_with_proof_of_work
123
137
  end
124
138
 
125
139
  def calc_hash
126
140
  sha = Digest::SHA256.new
127
- sha.update( @nonce.to_s + @index.to_s + @timestamp.to_s + @data + @previous_hash )
141
+ sha.update( @nonce.to_s +
142
+ @index.to_s +
143
+ @timestamp.to_s +
144
+ @transactions.to_s +
145
+ @transactions_count.to_s +
146
+ @previous_hash )
128
147
  sha.hexdigest
129
148
  end
130
149
  ...
@@ -144,8 +163,8 @@ for building and checking blockchains. Example:
144
163
  b = Blockchain.new # note: will (auto-) add the first (genesis) block
145
164
 
146
165
  b << 'Transaction Data...'
147
- b << 'Transaction Data......'
148
- b << 'More Transaction Data...'
166
+ b << 'Transaction Data...'
167
+ b << 'Transaction Data...'
149
168
 
150
169
  pp b
151
170
  ```
@@ -163,8 +182,8 @@ or use the `Blockchain` class as a wrapper (pass in the blockchain array):
163
182
  ``` ruby
164
183
  b0 = Block.first( 'Genesis' )
165
184
  b1 = Block.next( b0, 'Transaction Data...' )
166
- b2 = Block.next( b1, 'Transaction Data......' )
167
- b3 = Block.next( b2, 'More Transaction Data...' )
185
+ b2 = Block.next( b1, 'Transaction Data...' )
186
+ b3 = Block.next( b2, 'Transaction Data...' )
168
187
 
169
188
  blockchain = [b0, b1, b2, b3]
170
189
 
@@ -178,6 +197,90 @@ b.broken?
178
197
  and so on.
179
198
 
180
199
 
200
+ ### Transactions
201
+
202
+ Let's put the transactions from the (hyper) ledger book from [Tulips on the Blockchain!](https://github.com/openblockchains/tulips)
203
+ on the blockchain:
204
+
205
+
206
+ | From | To | What | Qty |
207
+ |---------------------|--------------|---------------------------|----:|
208
+ | Dutchgrown (†) | Vincent | Tulip Bloemendaal Sunset | 10 |
209
+ | Keukenhof (†) | Anne | Tulip Semper Augustus | 7 |
210
+ | | | | |
211
+ | Flowers (†) | Ruben | Tulip Admiral van Eijck | 5 |
212
+ | Vicent | Anne | Tulip Bloemendaal Sunset | 3 |
213
+ | Anne | Julia | Tulip Semper Augustus | 1 |
214
+ | Julia | Luuk | Tulip Semper Augustus | 1 |
215
+ | | | | |
216
+ | Bloom & Blossom (†) | Daisy | Tulip Admiral of Admirals | 8 |
217
+ | Vincent | Max | Tulip Bloemendaal Sunset | 2 |
218
+ | Anne | Martijn | Tulip Semper Augustus | 2 |
219
+ | Ruben | Julia | Tulip Admiral van Eijck | 2 |
220
+ | | | | |
221
+ | Teleflora (†) | Max | Tulip Red Impression | 11 |
222
+ | Anne | Naomi | Tulip Bloemendaal Sunset | 1 |
223
+ | Daisy | Vincent | Tulip Admiral of Admirals | 3 |
224
+ | Julia | Mina | Tulip Admiral van Eijck | 1 |
225
+
226
+ (†): Grower Transaction - New Tulips on the Market!
227
+
228
+
229
+ ```ruby
230
+ b0 = Block.first(
231
+ { from: "Dutchgrown", to: "Vincent", what: "Tulip Bloemendaal Sunset", qty: 10 },
232
+ { from: "Keukenhof", to: "Anne", what: "Tulip Semper Augustus", qty: 7 } )
233
+
234
+ b1 = Block.next( b0,
235
+ { from: "Flowers", to: "Ruben", what: "Tulip Admiral van Eijck", qty: 5 },
236
+ { from: "Vicent", to: "Anne", what: "Tulip Bloemendaal Sunset", qty: 3 },
237
+ { from: "Anne", to: "Julia", what: "Tulip Semper Augustus", qty: 1 },
238
+ { from: "Julia", to: "Luuk", what: "Tulip Semper Augustus", qty: 1 } )
239
+
240
+ b2 = Block.next( b1,
241
+ { from: "Bloom & Blossom", to: "Daisy", what: "Tulip Admiral of Admirals", qty: 8 },
242
+ { from: "Vincent", to: "Max", what: "Tulip Bloemendaal Sunset", qty: 2 },
243
+ { from: "Anne", to: "Martijn", what: "Tulip Semper Augustus", qty: 2 },
244
+ { from: "Ruben", to: "Julia", what: "Tulip Admiral van Eijck", qty: 2 } )
245
+ ...
246
+ ```
247
+
248
+ resulting in:
249
+
250
+ ```
251
+ [#<Block:0x2da3da0
252
+ @index = 0,
253
+ @timestamp = 1637-09-24 11:40:15,
254
+ @previous_hash = "0",
255
+ @hash = "32bd169baebba0b70491b748329ab631c85175be15e1672f924ca174f628cb66",
256
+ @transactions_count = 2,
257
+ @transactions =
258
+ [{:from=>"Dutchgrown", :to=>"Vincent", :what=>"Tulip Bloemendaal Sunset", :qty=>10},
259
+ {:from=>"Keukenhof", :to=>"Anne", :what=>"Tulip Semper Augustus", :qty=>7}]>,
260
+ #<Block:0x2da2ff0
261
+ @index = 1,
262
+ @timestamp = 1637-09-24 11:50:15,
263
+ @previous_hash = "32bd169baebba0b70491b748329ab631c85175be15e1672f924ca174f628cb66",
264
+ @hash = "57b519a8903e45348ac8a739c788815e2bd90423663957f87e276307f77f1028",
265
+ @transactions_count = 4,
266
+ @transactions =
267
+ [{:from=>"Flowers", :to=>"Ruben", :what=>"Tulip Admiral van Eijck", :qty=>5},
268
+ {:from=>"Vicent", :to=>"Anne", :what=>"Tulip Bloemendaal Sunset", :qty=>3},
269
+ {:from=>"Anne", :to=>"Julia", :what=>"Tulip Semper Augustus", :qty=>1},
270
+ {:from=>"Julia", :to=>"Luuk", :what=>"Tulip Semper Augustus", :qty=>1}]>,
271
+ #<Block:0x2da2720
272
+ @index = 2,
273
+ @timestamp = 1637-09-24 12:00:15,
274
+ @previous_hash = "57b519a8903e45348ac8a739c788815e2bd90423663957f87e276307f77f1028",
275
+ @hash = "ec7dd5ea86ab966d4d4db182abb7aa93c7e5f63857476e6301e7e38cebf36568",
276
+ @transactions_count = 4,
277
+ @transactions =
278
+ [{:from=>"Bloom & Blossom", :to=>"Daisy", :what=>"Tulip Admiral of Admirals", :qty=>8},
279
+ {:from=>"Vincent", :to=>"Max", :what=>"Tulip Bloemendaal Sunset", :qty=>2},
280
+ {:from=>"Anne", :to=>"Martijn", :what=>"Tulip Semper Augustus", :qty=>2},
281
+ {:from=>"Ruben", :to=>"Julia", :what=>"Tulip Admiral van Eijck", :qty=>2}]>,
282
+ ...
283
+ ```
181
284
 
182
285
 
183
286
  ## Install
@@ -8,33 +8,57 @@ class Block
8
8
 
9
9
  attr_reader :index
10
10
  attr_reader :timestamp
11
- attr_reader :data
11
+ attr_reader :transactions_count # use alias - txn_count - why? why not?
12
+ attr_reader :transactions # use alias - txn - why? why not?
12
13
  attr_reader :previous_hash
13
14
  attr_reader :hash
14
15
 
15
- def initialize(index, data, previous_hash)
16
- @index = index
17
- @timestamp = Time.now.utc ## note: use coordinated universal time (utc)
18
- @data = data
19
- @previous_hash = previous_hash
20
- @hash = calc_hash
16
+ def initialize(index, transactions, previous_hash, timestamp: nil)
17
+ @index = index
18
+
19
+ ## note: use coordinated universal time (utc)
20
+ ## auto-add timestamp for new blocks (e.g. timestamp is nil)
21
+ @timestamp = timestamp ? timestamp : Time.now.utc
22
+
23
+ ## note: assumes / expects an array for transactions
24
+ @transactions = transactions
25
+ @transactions_count = transactions.size
26
+
27
+ @previous_hash = previous_hash
28
+ @hash = calc_hash
21
29
  end
22
30
 
23
31
  def calc_hash
24
32
  sha = Digest::SHA256.new
25
- sha.update( @index.to_s + @timestamp.to_s + @data + @previous_hash )
33
+ sha.update( @index.to_s +
34
+ @timestamp.to_s +
35
+ @transactions.to_s +
36
+ @transactions_count.to_s +
37
+ @previous_hash )
26
38
  sha.hexdigest
27
39
  end
28
40
 
29
41
 
30
42
 
31
- def self.first( data='Genesis' ) # create genesis (big bang! first) block
43
+ def self.first( *transactions ) # create genesis (big bang! first) block
44
+ ## note: allow/support splat-* for now for convenience (auto-wraps args into array)
45
+ if transactions.size == 1 && transactions[0].is_a?( Array )
46
+ t = transactions[0] ## "unwrap" array in array
47
+ else
48
+ t = transactions ## use "auto-wrapped" splat array
49
+ end
32
50
  ## uses index zero (0) and arbitrary previous_hash ('0')
33
- Block.new( 0, data, '0' )
51
+ Block.new( 0, t, '0' )
34
52
  end
35
53
 
36
- def self.next( previous, data='Transaction Data...' )
37
- Block.new( previous.index+1, data, previous.hash )
54
+ def self.next( previous, *transactions )
55
+ ## note: allow/support splat-* for now for convenience (auto-wraps args into array)
56
+ if transactions.size == 1 && transactions[0].is_a?( Array )
57
+ t = transactions[0] ## "unwrap" array in array
58
+ else
59
+ t = transactions ## use "auto-wrapped" splat array
60
+ end
61
+ Block.new( previous.index+1, t, previous.hash )
38
62
  end
39
63
 
40
64
  end # class Block
@@ -9,35 +9,51 @@ class Blockchain
9
9
 
10
10
  def initialize( chain=nil, block_class: nil )
11
11
  if chain.nil?
12
- @block_class = block_class || BlockchainLite::ProofOfWork::Block
12
+ @block_class = if block_class
13
+ block_class
14
+ else
15
+ ## check if Block is defined
16
+ ## if yes, use it othwerwise fallback for ProofOfWork::Block
17
+ defined?( Block ) ? Block : BlockchainLite::ProofOfWork::Block
18
+ end
19
+
13
20
  b0 = @block_class.first( 'Genesis' )
14
21
  @chain = [b0]
15
22
  else
16
23
  @chain = chain # "wrap" passed in blockchain (in array)
17
- if block_class # configure block class ("factory")
18
- @block_class = block_class
19
- else
20
- ### no block class configured; use class of first block
21
- ## todo/fix: throw except if chain is empty (no class configured) - why? why not??
22
- @block_class = @chain.first.class if @chain.first
23
- end
24
+ @block_class = if block_class
25
+ block_class
26
+ else
27
+ ### no block class configured; use class of first block
28
+ if @chain.first
29
+ @chain.first.class
30
+ else
31
+ ## todo/fix: throw except if chain is empty (no class configured) - why? why not??
32
+ ## throw exception on add block if not a block - why? why not??
33
+ end
34
+ end
24
35
  end
25
36
  end
26
37
 
27
38
 
39
+
28
40
  def last() @chain.last; end ## return last block in chain
29
41
 
30
42
 
43
+ ###
44
+ ## make method-<< abstract/virtual - why? why not?
45
+ ## must be added by to make sure proper block_class is always used - why? why not??
46
+
31
47
  def <<( arg )
32
- if arg.is_a? String ## assume its (just) data
48
+ if arg.is_a? Array ## assume its (just) data
33
49
  data = arg
34
50
  bl = @chain.last
35
51
  b = @block_class.next( bl, data )
36
52
  elsif arg.class.respond_to?( :first ) && ## check if respond_to? Block.first? and Block.next? - assume it's a block
37
53
  arg.class.respond_to?( :next ) ## check/todo: use is_a? @block_class why? why not?
38
54
  b = arg
39
- else ## fallback; assume its (just) data (not a block)
40
- data = arg.to_s ## note: always convert arg to string!! - why? why not??
55
+ else ## fallback; assume single transaction record; wrap in array - allow fallback - why? why not??
56
+ data = [arg]
41
57
  bl = @chain.last
42
58
  b = @block_class.next( bl, data )
43
59
  end
@@ -8,36 +8,73 @@ class Block
8
8
 
9
9
  attr_reader :index
10
10
  attr_reader :timestamp
11
- attr_reader :data
11
+ attr_reader :transactions_count # use alias - txn_count - why? why not?
12
+ attr_reader :transactions # use alias - txn - why? why not?
12
13
  attr_reader :previous_hash
13
- attr_reader :nonce ## proof of work if hash starts with leading zeros (00)
14
+ attr_reader :nonce # ("lucky" number used once) - proof of work if hash starts with leading zeros (00)
14
15
  attr_reader :hash
15
16
 
16
- def initialize(index, data, previous_hash)
17
- @index = index
18
- @timestamp = Time.now.utc ## note: use coordinated universal time (utc)
19
- @data = data
17
+ def initialize(index, transactions, previous_hash, timestamp: nil, nonce: nil)
18
+ @index = index
19
+
20
+ ## note: assumes / expects an array for transactions
21
+ @transactions = transactions
22
+ @transactions_count = transactions.size
23
+
20
24
  @previous_hash = previous_hash
21
- @nonce, @hash = compute_hash_with_proof_of_work
25
+
26
+ ## note: use coordinated universal time (utc)
27
+ @timestamp = timestamp ? timestamp : Time.now.utc
28
+
29
+ if nonce ## restore pre-computed/mined block (from disk/cache/db/etc.)
30
+ ## todo: check timestamp MUST NOT be nil
31
+ @nonce = nonce
32
+ @hash = calc_hash
33
+ else ## new block (mine! e.g. find nonce - "lucky" number used once)
34
+ @nonce, @hash = compute_hash_with_proof_of_work
35
+ end
22
36
  end
23
37
 
24
38
  def calc_hash
25
- sha = Digest::SHA256.new
26
- sha.update( @nonce.to_s + @index.to_s + @timestamp.to_s + @data + @previous_hash )
27
- sha.hexdigest
39
+ calc_hash_with_nonce( @nonce )
28
40
  end
29
41
 
30
42
 
31
- def self.first( data='Genesis' ) # create genesis (big bang! first) block
43
+
44
+ def self.first( *transactions, **opts ) # create genesis (big bang! first) block
45
+ ## note: allow/support splat-* for now for convenience (auto-wraps args into array)
46
+ if transactions.size == 1 && transactions[0].is_a?( Array )
47
+ t = transactions[0] ## "unwrap" array in array
48
+ else
49
+ t = transactions ## use "auto-wrapped" splat array
50
+ end
32
51
  ## uses index zero (0) and arbitrary previous_hash ('0')
33
- Block.new( 0, data, '0' )
52
+ ## note: pass along (optional) custom timestamp (e.g. used for 1637 etc.)
53
+ Block.new( 0, t, '0', timestamp: opts[:timestamp] )
34
54
  end
35
55
 
36
- def self.next( previous, data='Transaction Data...' )
37
- Block.new( previous.index+1, data, previous.hash )
56
+ def self.next( previous, *transactions, **opts )
57
+ ## note: allow/support splat-* for now for convenience (auto-wraps args into array)
58
+ if transactions.size == 1 && transactions[0].is_a?( Array )
59
+ t = transactions[0] ## "unwrap" array in array
60
+ else
61
+ t = transactions ## use "auto-wrapped" splat array
62
+ end
63
+ Block.new( previous.index+1, t, previous.hash, timestamp: opts[:timestamp] )
38
64
  end
39
65
 
66
+
40
67
  private
68
+ def calc_hash_with_nonce( nonce=0 )
69
+ sha = Digest::SHA256.new
70
+ sha.update( nonce.to_s +
71
+ @index.to_s +
72
+ @timestamp.to_s +
73
+ @transactions.to_s +
74
+ @transactions_count.to_s +
75
+ @previous_hash )
76
+ sha.hexdigest
77
+ end
41
78
 
42
79
  def compute_hash_with_proof_of_work( difficulty='00' )
43
80
  nonce = 0
@@ -51,12 +88,6 @@ private
51
88
  end
52
89
  end
53
90
 
54
- def calc_hash_with_nonce( nonce=0 )
55
- sha = Digest::SHA256.new
56
- sha.update( nonce.to_s + @index.to_s + @timestamp.to_s + @data + @previous_hash )
57
- sha.hexdigest
58
- end
59
-
60
91
  end # class Block
61
92
 
62
93
 
@@ -4,7 +4,7 @@
4
4
  module BlockchainLite
5
5
 
6
6
  MAJOR = 1
7
- MINOR = 1
7
+ MINOR = 2
8
8
  PATCH = 0
9
9
  VERSION = [MAJOR,MINOR,PATCH].join('.')
10
10
 
data/test/test_block.rb CHANGED
@@ -18,14 +18,78 @@ def test_version
18
18
  assert true ## (for now) everything ok if we get here
19
19
  end
20
20
 
21
+
21
22
  def test_example
22
23
 
23
24
  b0 = Block.first( 'Genesis' )
24
25
  b1 = Block.next( b0, 'Transaction Data...' )
25
- b2 = Block.next( b1, 'Transaction Data......' )
26
- b3 = Block.next( b2, 'More Transaction Data...' )
26
+ b2 = Block.next( b1, 'Transaction Data...', 'Transaction Data...' )
27
+ b3 = Block.next( b2 ) ## no transaction data
28
+ b4 = Block.next( b3, ['Transaction Data...', 'Transaction Data...'] )
29
+
30
+ blockchain = [b0, b1, b2, b3, b4]
31
+
32
+ pp blockchain
33
+
34
+ assert true ## (for now) everything ok if we get here
35
+ end
36
+
37
+ def test_tulips_example
38
+ b0 = Block.first(
39
+ { from: "Dutchgrown", to: "Vincent", what: "Tulip Bloemendaal Sunset", qty: 10 },
40
+ { from: "Keukenhof", to: "Anne", what: "Tulip Semper Augustus", qty: 7 } )
41
+
42
+ b1 = Block.next( b0,
43
+ { from: "Flowers", to: "Ruben", what: "Tulip Admiral van Eijck", qty: 5 },
44
+ { from: "Vicent", to: "Anne", what: "Tulip Bloemendaal Sunset", qty: 3 },
45
+ { from: "Anne", to: "Julia", what: "Tulip Semper Augustus", qty: 1 },
46
+ { from: "Julia", to: "Luuk", what: "Tulip Semper Augustus", qty: 1 } )
47
+
48
+ b2 = Block.next( b1,
49
+ { from: "Bloom & Blossom", to: "Daisy", what: "Tulip Admiral of Admirals", qty: 8 },
50
+ { from: "Vincent", to: "Max", what: "Tulip Bloemendaal Sunset", qty: 2 },
51
+ { from: "Anne", to: "Martijn", what: "Tulip Semper Augustus", qty: 2 },
52
+ { from: "Ruben", to: "Julia", what: "Tulip Admiral van Eijck", qty: 2 } )
53
+
54
+ blockchain = [b0, b1, b2]
55
+
56
+ pp blockchain
57
+
58
+ assert true ## (for now) everything ok if we get here
59
+ end
60
+
61
+
62
+ def timestamp1637
63
+ ## change year to 1637 :-)
64
+ ## note: time (uses signed integer e.g. epoch/unix time starting in 1970 with 0)
65
+ ## todo: add nano/mili-seconds - why? why not? possible?
66
+ now = Time.now.utc.to_datetime
67
+ past = DateTime.new( 1637, now.month, now.mday, now.hour, now.min, now.sec, now.zone )
68
+ past
69
+ end
70
+
71
+ def test_tulips_1637_example
72
+
73
+ b0 = Block.first(
74
+ { from: "Dutchgrown", to: "Vincent", what: "Tulip Bloemendaal Sunset", qty: 10 },
75
+ { from: "Keukenhof", to: "Anne", what: "Tulip Semper Augustus", qty: 7 },
76
+ timestamp: timestamp1637 )
77
+
78
+ b1 = Block.next( b0,
79
+ { from: "Flowers", to: "Ruben", what: "Tulip Admiral van Eijck", qty: 5 },
80
+ { from: "Vicent", to: "Anne", what: "Tulip Bloemendaal Sunset", qty: 3 },
81
+ { from: "Anne", to: "Julia", what: "Tulip Semper Augustus", qty: 1 },
82
+ { from: "Julia", to: "Luuk", what: "Tulip Semper Augustus", qty: 1 },
83
+ timestamp: timestamp1637 )
84
+
85
+ b2 = Block.next( b1,
86
+ { from: "Bloom & Blossom", to: "Daisy", what: "Tulip Admiral of Admirals", qty: 8 },
87
+ { from: "Vincent", to: "Max", what: "Tulip Bloemendaal Sunset", qty: 2 },
88
+ { from: "Anne", to: "Martijn", what: "Tulip Semper Augustus", qty: 2 },
89
+ { from: "Ruben", to: "Julia", what: "Tulip Admiral van Eijck", qty: 2 },
90
+ timestamp: timestamp1637 )
27
91
 
28
- blockchain = [b0, b1, b2, b3]
92
+ blockchain = [b0, b1, b2]
29
93
 
30
94
  pp blockchain
31
95
 
@@ -16,10 +16,11 @@ def test_example
16
16
 
17
17
  b0 = block_class.first( 'Genesis' )
18
18
  b1 = block_class.next( b0, 'Transaction Data...' )
19
- b2 = block_class.next( b1, 'Transaction Data......' )
20
- b3 = block_class.next( b2, 'More Transaction Data...' )
19
+ b2 = block_class.next( b1, 'Transaction Data...', 'Transaction Data...' )
20
+ b3 = block_class.next( b2 ) ## no transaction data
21
+ b4 = block_class.next( b3, ['Transaction Data...', 'Transaction Data...'] )
21
22
 
22
- blockchain = [b0, b1, b2, b3]
23
+ blockchain = [b0, b1, b2, b3, b4]
23
24
 
24
25
  pp blockchain
25
26
 
@@ -16,10 +16,11 @@ def test_example
16
16
 
17
17
  b0 = block_class.first( 'Genesis' )
18
18
  b1 = block_class.next( b0, 'Transaction Data...' )
19
- b2 = block_class.next( b1, 'Transaction Data......' )
20
- b3 = block_class.next( b2, 'More Transaction Data...' )
19
+ b2 = block_class.next( b1, 'Transaction Data...', 'Transaction Data...' )
20
+ b3 = block_class.next( b2 ) ## no transaction data
21
+ b4 = block_class.next( b3, ['Transaction Data...', 'Transaction Data...'] )
21
22
 
22
- blockchain = [b0, b1, b2, b3]
23
+ blockchain = [b0, b1, b2, b3, b4]
23
24
 
24
25
  pp blockchain
25
26
 
@@ -14,11 +14,14 @@ def test_new
14
14
  b = Blockchain.new
15
15
 
16
16
  b << 'Transaction Data...'
17
+ b << ['Transaction Data...']
18
+ b << ['Transaction Data...', 'Transaction Data...']
19
+ b << [] ## empty block (no transactions)
17
20
 
18
21
  ## add do-it-yourself built block
19
- b << Block.next( b.last, 'Transaction Data......' )
22
+ b << Block.next( b.last, 'Transaction Data...' )
20
23
 
21
- b << 'More Transaction Data...'
24
+ b << 'Transaction Data...'
22
25
 
23
26
  pp b
24
27
 
@@ -31,8 +34,8 @@ def test_with_block_class
31
34
  b = Blockchain.new( block_class: BlockchainLite::Basic::Block )
32
35
 
33
36
  b << 'Transaction Data...'
34
- b << 'Transaction Data......'
35
- b << 'More Transaction Data...'
37
+ b << 'Transaction Data...'
38
+ b << 'Transaction Data...'
36
39
 
37
40
  pp b
38
41
 
@@ -44,8 +47,8 @@ def test_wrap
44
47
 
45
48
  b0 = Block.first( 'Genesis' )
46
49
  b1 = Block.next( b0, 'Transaction Data...' )
47
- b2 = Block.next( b1, 'Transaction Data......' )
48
- b3 = Block.next( b2, 'More Transaction Data...' )
50
+ b2 = Block.next( b1, 'Transaction Data...' )
51
+ b3 = Block.next( b2, 'Transaction Data...' )
49
52
  blockchain = [b0, b1, b2, b3]
50
53
 
51
54
  b = Blockchain.new( blockchain )
@@ -58,7 +61,7 @@ def test_wrap
58
61
  assert_equal true, b.valid?
59
62
 
60
63
  ## corrupt data in block in chain
61
- b2.instance_eval %{ @data='XXXXXXX' }
64
+ b2.instance_eval %{ @transactions=['XXXXXXX'] }
62
65
 
63
66
  assert_equal true, b.broken?
64
67
  assert_equal false, b.valid?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blockchain-lite
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.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-09-23 00:00:00.000000000 Z
11
+ date: 2017-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc