ciri 0.0.2 → 0.0.3

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.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rspec +0 -1
  4. data/Gemfile.lock +11 -7
  5. data/LICENSE.txt +201 -21
  6. data/README.md +78 -25
  7. data/Rakefile +45 -17
  8. data/bin/bundle +105 -0
  9. data/bin/htmldiff +29 -0
  10. data/bin/ldiff +29 -0
  11. data/bin/rake +29 -0
  12. data/bin/rspec +29 -0
  13. data/ciri-crypto/.gitignore +11 -0
  14. data/ciri-crypto/.rspec +3 -0
  15. data/ciri-crypto/.travis.yml +5 -0
  16. data/ciri-crypto/CODE_OF_CONDUCT.md +74 -0
  17. data/ciri-crypto/Gemfile +6 -0
  18. data/ciri-crypto/Gemfile.lock +43 -0
  19. data/ciri-crypto/LICENSE.txt +201 -0
  20. data/ciri-crypto/README.md +58 -0
  21. data/ciri-crypto/Rakefile +6 -0
  22. data/ciri-crypto/bin/console +14 -0
  23. data/ciri-crypto/bin/setup +8 -0
  24. data/ciri-crypto/ciri-crypto.gemspec +40 -0
  25. data/ciri-crypto/lib/ciri/crypto/errors.rb +29 -0
  26. data/ciri-crypto/lib/ciri/crypto/signature.rb +71 -0
  27. data/ciri-crypto/lib/ciri/crypto/version.rb +5 -0
  28. data/{lib → ciri-crypto/lib}/ciri/crypto.rb +16 -69
  29. data/ciri-crypto/spec/ciri/crypto_spec.rb +56 -0
  30. data/ciri-crypto/spec/spec_helper.rb +14 -0
  31. data/ciri-rlp/Gemfile.lock +5 -5
  32. data/ciri-rlp/LICENSE.txt +201 -21
  33. data/ciri-rlp/README.md +1 -1
  34. data/ciri-rlp/ciri-rlp.gemspec +3 -3
  35. data/ciri-rlp/lib/ciri/rlp/decode.rb +10 -16
  36. data/ciri-rlp/lib/ciri/rlp/encode.rb +10 -16
  37. data/ciri-rlp/lib/ciri/rlp/serializable.rb +10 -16
  38. data/ciri-rlp/lib/ciri/rlp.rb +10 -16
  39. data/ciri-rlp/spec/ciri/fixture_spec.rb +10 -16
  40. data/ciri-rlp/spec/ciri/rlp/serializable_spec.rb +10 -16
  41. data/ciri-utils/Gemfile.lock +4 -4
  42. data/ciri-utils/LICENSE.txt +201 -21
  43. data/ciri-utils/README.md +1 -1
  44. data/ciri-utils/ciri-utils.gemspec +2 -2
  45. data/ciri-utils/lib/ciri/utils/logger.rb +10 -16
  46. data/ciri-utils/lib/ciri/utils/number.rb +10 -16
  47. data/ciri-utils/lib/ciri/utils/version.rb +1 -1
  48. data/ciri-utils/lib/ciri/utils.rb +3 -3
  49. data/ciri.gemspec +4 -3
  50. data/docker/{Base → Dockerfile} +9 -3
  51. data/lib/ciri/actor.rb +10 -16
  52. data/lib/ciri/bloom_filter.rb +11 -17
  53. data/lib/ciri/chain/block.rb +10 -16
  54. data/lib/ciri/chain/header.rb +12 -18
  55. data/lib/ciri/chain/header_chain.rb +8 -22
  56. data/lib/ciri/chain/transaction.rb +38 -33
  57. data/lib/ciri/chain.rb +27 -26
  58. data/lib/ciri/core_ext.rb +61 -0
  59. data/lib/ciri/db/account_db.rb +25 -21
  60. data/lib/ciri/db/backend/memory.rb +10 -16
  61. data/lib/ciri/db/backend/rocks.rb +10 -16
  62. data/lib/ciri/db/backend/rocks_db.rb +10 -16
  63. data/lib/ciri/devp2p/peer.rb +10 -16
  64. data/lib/ciri/devp2p/protocol.rb +10 -16
  65. data/lib/ciri/devp2p/protocol_io.rb +10 -16
  66. data/lib/ciri/devp2p/rlpx/connection.rb +10 -16
  67. data/lib/ciri/devp2p/rlpx/encryption_handshake.rb +13 -19
  68. data/lib/ciri/devp2p/rlpx/error.rb +10 -16
  69. data/lib/ciri/devp2p/rlpx/frame_io.rb +10 -16
  70. data/lib/ciri/devp2p/rlpx/message.rb +10 -16
  71. data/lib/ciri/devp2p/rlpx/node.rb +10 -16
  72. data/lib/ciri/devp2p/rlpx/protocol_handshake.rb +10 -16
  73. data/lib/ciri/devp2p/rlpx/protocol_messages.rb +10 -16
  74. data/lib/ciri/devp2p/rlpx/secrets.rb +10 -16
  75. data/lib/ciri/devp2p/rlpx.rb +10 -16
  76. data/lib/ciri/devp2p/server.rb +10 -16
  77. data/lib/ciri/eth/peer.rb +10 -16
  78. data/lib/ciri/eth/protocol_manage.rb +10 -16
  79. data/lib/ciri/eth/protocol_messages.rb +10 -16
  80. data/lib/ciri/eth/synchronizer.rb +10 -16
  81. data/lib/ciri/eth.rb +10 -16
  82. data/lib/ciri/ethash.rb +10 -16
  83. data/lib/ciri/evm/block_info.rb +25 -17
  84. data/lib/ciri/evm/errors.rb +13 -16
  85. data/lib/ciri/evm/execution_context.rb +136 -0
  86. data/lib/ciri/evm/instruction.rb +17 -24
  87. data/lib/ciri/evm/log_entry.rb +12 -18
  88. data/lib/ciri/evm/machine_state.rb +28 -33
  89. data/lib/ciri/evm/op.rb +52 -89
  90. data/lib/ciri/evm/op_call.rb +114 -0
  91. data/lib/ciri/evm/precompile_contract.rb +102 -0
  92. data/lib/ciri/evm/state.rb +28 -21
  93. data/lib/ciri/evm/sub_state.rb +18 -24
  94. data/lib/ciri/evm/vm.rb +128 -190
  95. data/lib/ciri/evm.rb +77 -85
  96. data/lib/ciri/forks/base.rb +28 -16
  97. data/lib/ciri/forks/byzantium.rb +43 -0
  98. data/lib/ciri/forks/config.rb +36 -0
  99. data/lib/ciri/forks/frontier/cost.rb +42 -33
  100. data/lib/ciri/forks/frontier.rb +47 -18
  101. data/lib/ciri/forks/homestead/cost.rb +195 -0
  102. data/lib/ciri/forks/homestead.rb +46 -0
  103. data/lib/ciri/forks.rb +12 -22
  104. data/lib/ciri/key.rb +14 -3
  105. data/lib/ciri/pow.rb +11 -17
  106. data/lib/ciri/rlp/decode.rb +10 -16
  107. data/lib/ciri/rlp/encode.rb +10 -16
  108. data/lib/ciri/rlp/serializable.rb +10 -16
  109. data/lib/ciri/serialize.rb +14 -17
  110. data/lib/ciri/trie/nibbles.rb +10 -16
  111. data/lib/ciri/trie/nodes.rb +12 -17
  112. data/lib/ciri/trie.rb +12 -18
  113. data/lib/ciri/types/account.rb +15 -17
  114. data/lib/ciri/types/address.rb +11 -17
  115. data/lib/ciri/types/errors.rb +10 -16
  116. data/lib/ciri/types/receipt.rb +12 -18
  117. data/lib/ciri/types/uint.rb +79 -0
  118. data/lib/ciri/version.rb +1 -1
  119. data/lib/ciri.rb +10 -16
  120. metadata +54 -10
  121. data/lib/ciri/types/number.rb +0 -73
@@ -1,26 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
3
+ # Copyright 2018 Jiang Jinyang <https://justjjy.com>
4
4
  #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
11
8
  #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
9
+ # http://www.apache.org/licenses/LICENSE-2.0
14
10
  #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
22
16
 
23
17
 
18
+ require 'ciri/utils/logger'
24
19
  require 'ciri/serialize'
25
20
  require 'ciri/evm/errors'
26
21
 
@@ -29,23 +24,13 @@ module Ciri
29
24
 
30
25
  # represent current vm status, include stack, memory..
31
26
  class MachineState
27
+ include Utils::Logger
32
28
 
33
- attr_reader :remain_gas, :memory, :stack
34
- attr_accessor :pc, :output, :memory_item
29
+ attr_reader :memory, :stack
35
30
 
36
- def initialize(remain_gas:, pc:, memory:, memory_item:, stack:, output: ''.b)
37
- raise ArgumentError.new("remain_gas must more than 0") if remain_gas < 0
38
- @remain_gas = remain_gas
39
- @pc = pc
31
+ def initialize(memory: ''.b, stack: [])
40
32
  @memory = memory
41
- @memory_item = memory_item
42
33
  @stack = stack
43
- @output = output
44
- end
45
-
46
- def consume_gas(gas)
47
- raise GasNotEnoughError.new("can't consume gas to negative, remain_gas: #{remain_gas}, consumed: #{gas}") if gas > remain_gas
48
- @remain_gas -= gas
49
34
  end
50
35
 
51
36
  # fetch a list of items from stack
@@ -72,7 +57,7 @@ module Ciri
72
57
 
73
58
  # store data to memory
74
59
  def memory_store(start, size, data)
75
- if start < memory.size && start + size - 1 < memory.size
60
+ if size > 0 && start < memory.size && start + size - 1 < memory.size
76
61
  memory[start..(start + size - 1)] = Serialize.serialize(data).rjust(size, "\x00".b)
77
62
  end
78
63
  end
@@ -87,10 +72,20 @@ module Ciri
87
72
  end
88
73
  end
89
74
 
75
+ def memory_item
76
+ Utils.ceil_div(memory.size, 32)
77
+ end
78
+
90
79
  # extend vm memory, used for memory_gas calculation
91
- def extend_memory(pos, size)
92
- if size != 0 && (i = Utils.ceil_div(pos + size, 32)) > memory_item
93
- self.memory_item = i
80
+ def extend_memory(context, pos, size)
81
+ if size != 0 && (new_item = Utils.ceil_div(pos + size, 32)) > memory_item
82
+ debug("extend memory: from #{memory_item} -> #{new_item}")
83
+ old_cost_gas = context.fork_schema.gas_of_memory memory_item
84
+ new_cost_gas = context.fork_schema.gas_of_memory new_item
85
+ context.consume_gas(new_cost_gas - old_cost_gas)
86
+
87
+ extend_size = (new_item - memory_item) * 32
88
+ self.memory << "\x00".b * extend_size
94
89
  end
95
90
  end
96
91
 
data/lib/ciri/evm/op.rb CHANGED
@@ -1,29 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
3
+ # Copyright 2018 Jiang Jinyang <https://justjjy.com>
4
4
  #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
11
8
  #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
9
+ # http://www.apache.org/licenses/LICENSE-2.0
14
10
  #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
22
16
 
23
17
 
24
18
  require 'ciri/utils'
25
19
  require 'ciri/utils/number'
26
20
  require 'ciri/types/address'
21
+ require_relative 'op_call'
27
22
 
28
23
  module Ciri
29
24
  class EVM
@@ -206,7 +201,8 @@ module Ciri
206
201
  # 20s: sha3
207
202
  def_op :SHA3, 0x20, 2, 1 do |vm|
208
203
  pos, size = vm.pop_list(2, Integer)
209
- hashed = Ciri::Utils.sha3 vm.memory_fetch(pos, size)
204
+ vm.extend_memory(pos, size)
205
+ hashed = Ciri::Utils.keccak vm.memory_fetch(pos, size)
210
206
  vm.extend_memory(pos, size)
211
207
  vm.push hashed
212
208
  end
@@ -246,8 +242,8 @@ module Ciri
246
242
  def_op :CALLDATACOPY, 0x37, 3, 0 do |vm|
247
243
  mem_pos, data_pos, size = vm.pop_list(3, Integer)
248
244
  data = vm.get_data(data_pos, size)
249
- vm.memory_store(mem_pos, size, data)
250
245
  vm.extend_memory(mem_pos, size)
246
+ vm.memory_store(mem_pos, size, data)
251
247
  end
252
248
 
253
249
  def_op :CODESIZE, 0x38, 0, 1 do |vm|
@@ -257,6 +253,7 @@ module Ciri
257
253
  def_op :CODECOPY, 0x39, 3, 0 do |vm|
258
254
  mem_pos, code_pos, size = vm.pop_list(3, Integer)
259
255
  data = vm.get_code(code_pos, size)
256
+ vm.extend_memory(mem_pos, size)
260
257
  vm.memory_store(mem_pos, size, data)
261
258
  end
262
259
 
@@ -283,6 +280,7 @@ module Ciri
283
280
  else
284
281
  code[data_pos..data_end_pos]
285
282
  end
283
+ vm.extend_memory(mem_pos, size)
286
284
  vm.memory_store(mem_pos, size, data)
287
285
  end
288
286
 
@@ -290,7 +288,14 @@ module Ciri
290
288
  RETURNDATACOPY = 0x3e
291
289
 
292
290
  # 40s: block information
293
- BLOCKHASH = 0x40
291
+ def_op :BLOCKHASH, 0x40, 1, 1 do |vm|
292
+ height = vm.pop(Integer)
293
+ # cause current block hash do not exists in chain
294
+ # here we compute distance of parent height and ancestor height
295
+ # and use parent_hash to find ancestor hash
296
+ distance = vm.block_info.number - height - 1
297
+ vm.push vm.state.get_ancestor_hash(vm.block_info.parent_hash, distance)
298
+ end
294
299
 
295
300
  def_op :COINBASE, 0x41, 0, 1 do |vm|
296
301
  vm.push vm.block_info.coinbase
@@ -319,22 +324,22 @@ module Ciri
319
324
 
320
325
  def_op :MLOAD, 0x51, 1, 1 do |vm|
321
326
  index = vm.pop(Integer)
322
- vm.push vm.memory_fetch(index, 32)
323
327
  vm.extend_memory(index, 32)
328
+ vm.push vm.memory_fetch(index, 32)
324
329
  end
325
330
 
326
331
  def_op :MSTORE, 0x52, 2, 0 do |vm|
327
332
  index = vm.pop(Integer)
328
333
  data = vm.pop
329
- vm.memory_store(index, 32, data)
330
334
  vm.extend_memory(index, 32)
335
+ vm.memory_store(index, 32, data)
331
336
  end
332
337
 
333
338
  def_op :MSTORE8, 0x53, 2, 0 do |vm|
334
339
  index = vm.pop(Integer)
335
340
  data = vm.pop(Integer)
336
- vm.memory_store(index, 1, data % 256)
337
341
  vm.extend_memory(index, 8)
342
+ vm.memory_store(index, 1, data % 256)
338
343
  end
339
344
 
340
345
  def_op :SLOAD, 0x54, 1, 1 do |vm|
@@ -356,10 +361,12 @@ module Ciri
356
361
 
357
362
  def_op :JUMPI, 0x57, 2, 0 do |vm|
358
363
  dest, cond = vm.pop_list(2, Integer)
364
+ # if cond is non zero jump to dest, else just goto next pc
359
365
  if cond != 0
360
366
  vm.jump_to(dest)
361
367
  else
362
- vm.jump_to(vm.pc + 1)
368
+ # clear jump_to
369
+ vm.jump_to(nil)
363
370
  end
364
371
  end
365
372
 
@@ -372,7 +379,7 @@ module Ciri
372
379
  end
373
380
 
374
381
  def_op :GAS, 0x5a, 0, 1 do |vm|
375
- vm.push vm.machine_state.remain_gas
382
+ vm.push vm.remain_gas
376
383
  end
377
384
 
378
385
  def_op :JUMPDEST, 0x5b, 0, 0
@@ -417,8 +424,8 @@ module Ciri
417
424
  def_op name, 0xa0 + i, i + 2, 0, &(proc do |i|
418
425
  proc do |vm|
419
426
  pos, size = vm.pop_list(2, Integer)
420
- log_data = vm.memory_fetch(pos, size)
421
427
  vm.extend_memory(pos, size)
428
+ log_data = vm.memory_fetch(pos, size)
422
429
  topics = vm.pop_list(i, Integer)
423
430
  vm.add_log_entry(topics, log_data)
424
431
  end
@@ -430,75 +437,39 @@ module Ciri
430
437
  value = vm.pop(Integer)
431
438
  mem_pos, size = vm.pop_list(2, Integer)
432
439
 
433
- init = vm.memory_fetch(mem_pos, size)
434
440
  vm.extend_memory(mem_pos, size)
435
441
 
436
- contract_address, _ = vm.create_contract(value: value, init: init)
437
- vm.push contract_address
442
+ # have not enough money
443
+ if vm.find_account(vm.instruction.address).balance < value
444
+ vm.push(0)
445
+ else
446
+ init = vm.memory_fetch(mem_pos, size)
447
+ create_gas = vm.remain_gas
448
+ vm.consume_gas(create_gas)
449
+ child_context = vm.execution_context.child_context(gas_limit: create_gas)
450
+ contract_address, _ = vm.create_contract(value: value, init: init, touch_nonce: true, context: child_context)
451
+ vm.execution_context.return_gas(child_context.remain_gas)
452
+
453
+ vm.push contract_address
454
+ end
438
455
  end
439
456
 
440
457
  def_op :CALL, 0xf1, 7, 1 do |vm|
441
- vm.pop
442
- target = vm.pop(Address)
443
- value = vm.pop(Integer)
444
- input_mem_pos, input_size = vm.pop_list(2, Integer)
445
- output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
446
-
447
- data = vm.memory_fetch(input_mem_pos, input_size)
448
- vm.extend_memory(input_mem_pos, input_size)
449
-
450
- status, output = vm.call_message(sender: vm.instruction.address, value: value,
451
- data: data, receipt: target, code_address: target)
452
-
453
- output_size = [output_mem_size, output.size].min
454
- vm.memory_store(output_mem_pos, output_size, output)
455
- vm.extend_memory(output_mem_pos, output_size)
456
- vm.push status
458
+ OPCall::Call.new.call(vm)
457
459
  end
458
460
 
459
461
  def_op :CALLCODE, 0xf2, 7, 1 do |vm|
460
- # this method consume 7 items from stack, but seems not all of them are used
461
- # skip item
462
- vm.pop
463
- target = vm.pop(Address)
464
- value = vm.pop(Integer)
465
- input_mem_pos, input_size = vm.pop_list(2, Integer)
466
- output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
467
-
468
- data = vm.memory_fetch(input_mem_pos, input_size)
469
- vm.extend_memory(input_mem_pos, input_size)
470
-
471
- status, output = vm.call_message(sender: vm.instruction.address, value: value,
472
- data: data, receipt: vm.instruction.address, code_address: target)
473
-
474
- output_size = [output_mem_size, output.size].min
475
- vm.memory_store(output_mem_pos, output_size, output)
476
- vm.extend_memory(output_mem_pos, output_size)
477
- vm.push status
462
+ OPCall::CallCode.new.call(vm)
478
463
  end
479
464
 
480
465
  def_op :RETURN, 0xf3, 2, 0 do |vm|
481
466
  index, size = vm.pop_list(2, Integer)
482
- vm.output = vm.memory_fetch(index, size)
483
467
  vm.extend_memory(index, size)
468
+ vm.set_output vm.memory_fetch(index, size)
484
469
  end
485
470
 
486
- def_op :DELEGATECALL, 0xf4, 6, 1 do |vm|
487
- vm.pop
488
- target = vm.pop(Address)
489
- input_mem_pos, input_size = vm.pop_list(2, Integer)
490
- output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
491
-
492
- data = vm.memory_fetch(input_mem_pos, input_size)
493
- vm.extend_memory(input_mem_pos, input_size)
494
-
495
- status, output = vm.call_message(sender: vm.instruction.sender, value: vm.instruction.value,
496
- data: data, receipt: vm.instruction.address, code_address: target)
497
-
498
- output_size = [output_mem_size, output.size].min
499
- vm.memory_store(output_mem_pos, output_size, output)
500
- vm.extend_memory(output_mem_pos, output_size)
501
- vm.push status
471
+ def_op :DELEGATECALL, -0xf4, 6, 1 do |vm|
472
+ OPCall::DelegateCall.new.call(vm)
502
473
  end
503
474
 
504
475
  STATICCALL = 0xfa
@@ -516,18 +487,10 @@ module Ciri
516
487
 
517
488
  def_op :SELFDESTRUCT, 0xff, 1, 0 do |vm|
518
489
  refund_address = vm.pop(Address)
519
- refund_account = vm.find_account(refund_address)
520
-
521
490
  contract_account = vm.find_account vm.instruction.address
522
491
 
523
- if refund_address != vm.instruction.address
524
- refund_account.balance += contract_account.balance
525
- end
526
-
527
- contract_account.balance = 0
528
-
529
- vm.state.set_balance(refund_address, refund_account.balance)
530
- vm.state.set_balance(vm.instruction.address, contract_account.balance)
492
+ vm.state.add_balance(refund_address, contract_account.balance)
493
+ vm.state.set_balance(vm.instruction.address, 0)
531
494
 
532
495
  # register changed accounts
533
496
  vm.add_refund_account(refund_address)
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2018 Jiang Jinyang <https://justjjy.com>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+
18
+ require 'ciri/types/address'
19
+
20
+ module Ciri
21
+ class EVM
22
+ # handle EVM call operations
23
+ module OPCall
24
+ class Base
25
+
26
+ include Types
27
+
28
+ def call(vm)
29
+ raise NotImplementedError
30
+ end
31
+
32
+ def extract_call_argument(vm)
33
+ gas = vm.pop(Integer)
34
+ to = vm.pop(Address)
35
+ value = vm.pop(Integer)
36
+ input_mem_pos, input_size = vm.pop_list(2, Integer)
37
+ output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
38
+
39
+ # extend input output memory
40
+ vm.extend_memory(input_mem_pos, input_size)
41
+ vm.extend_memory(output_mem_pos, output_mem_size)
42
+
43
+ data = vm.memory_fetch(input_mem_pos, input_size)
44
+ [gas, to, value, data, output_mem_pos, output_mem_size]
45
+ end
46
+
47
+ def call_message(vm:, gas:, sender:, value:, data:, to:, code_address: to, output_mem_pos:, output_mem_size:)
48
+ context = vm.execution_context
49
+ child_gas_limit, child_gas_fee = context.fork_schema.gas_of_call(vm: vm,
50
+ gas: gas, to: to, value: value)
51
+ context.consume_gas(child_gas_fee)
52
+ if context.depth + 1 > 1024
53
+ context.return_gas(child_gas_limit)
54
+ vm.push 0
55
+ return
56
+ end
57
+ child_context = context.child_context(gas_limit: child_gas_limit)
58
+ child_context.instruction.sender = sender
59
+ child_context.instruction.value = value
60
+ child_context.instruction.data = data
61
+ child_context.instruction.address = to
62
+ child_context.instruction.bytes_code = vm.state.get_account_code(code_address)
63
+ status, output = vm.call_message(code_address: code_address, context: child_context)
64
+
65
+ context.return_gas(child_context.remain_gas)
66
+ output_size = [output_mem_size, output.size].min
67
+ vm.extend_memory(output_mem_pos, output_size)
68
+ vm.memory_store(output_mem_pos, output_size, output)
69
+ vm.push status
70
+ end
71
+ end
72
+
73
+ class Call < Base
74
+ def call(vm)
75
+ gas, to, value, data, output_mem_pos, output_mem_size = extract_call_argument(vm)
76
+ call_message(vm: vm, sender: vm.instruction.address, value: value, gas: gas, to: to,
77
+ data: data, code_address: to, output_mem_pos: output_mem_pos, output_mem_size: output_mem_size)
78
+ end
79
+ end
80
+
81
+ class CallCode < Base
82
+ def call(vm)
83
+ gas, to, value, data, output_mem_pos, output_mem_size = extract_call_argument(vm)
84
+ call_message(vm: vm, sender: vm.instruction.address, value: value, gas: gas, to: vm.instruction.address,
85
+ data: data, code_address: to, output_mem_pos: output_mem_pos, output_mem_size: output_mem_size)
86
+ end
87
+ end
88
+
89
+ class DelegateCall < Base
90
+ def call(vm)
91
+ gas, to, data, output_mem_pos, output_mem_size = extract_call_argument(vm)
92
+ call_message(vm: vm, sender: vm.instruction.sender, value: vm.instruction.value, gas: gas,
93
+ to: vm.instruction.address, data: data, code_address: to,
94
+ output_mem_pos: output_mem_pos, output_mem_size: output_mem_size)
95
+ end
96
+
97
+ def extract_call_argument(vm)
98
+ gas = vm.pop(Integer)
99
+ to = vm.pop(Address)
100
+ input_mem_pos, input_size = vm.pop_list(2, Integer)
101
+ output_mem_pos, output_mem_size = vm.pop_list(2, Integer)
102
+
103
+ # extend input output memory
104
+ vm.extend_memory(input_mem_pos, input_size)
105
+ vm.extend_memory(output_mem_pos, output_mem_size)
106
+
107
+ data = vm.memory_fetch(input_mem_pos, input_size)
108
+ [gas, to, data, output_mem_pos, output_mem_size]
109
+ end
110
+ end
111
+
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2018 Jiang Jinyang <https://justjjy.com>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+
18
+ require 'ciri/core_ext'
19
+ require 'ciri/crypto'
20
+ require 'digest'
21
+
22
+ using Ciri::CoreExt
23
+
24
+ module Ciri
25
+ class EVM
26
+ module PrecompileContract
27
+
28
+ class ECRecover
29
+ GAS_ECRECOVER = 3000
30
+
31
+ def call(vm)
32
+ vm.consume_gas(GAS_ECRECOVER)
33
+ message_hash = vm.instruction.data[0...32].pad_zero(32)
34
+
35
+ v = vm.instruction.data[32...64].decode_big_endian
36
+ r = vm.instruction.data[64...96].decode_big_endian
37
+ s = vm.instruction.data[96...128].decode_big_endian
38
+ unless valid_vrs?(v, r, s)
39
+ return vm.set_exception(Error.new("invalid vrs"))
40
+ end
41
+ raw_v = v - 27
42
+ begin
43
+ signature = Ciri::Crypto::Signature.new(vrs: [raw_v, r, s])
44
+ key = Ciri::Key.ecdsa_recover(message_hash, signature)
45
+ rescue StandardError => e
46
+ return vm.set_exception(e)
47
+ end
48
+
49
+ vm.set_output(key.to_address.to_s)
50
+ end
51
+
52
+ def valid_vrs?(v, r, s)
53
+ return false unless r < Ciri::Crypto::SECP256K1N
54
+ return false unless s < Ciri::Crypto::SECP256K1N
55
+ return false unless v == 28 || v == 27
56
+ true
57
+ end
58
+ end
59
+
60
+ class SHA256
61
+ GAS_SHA256 = 60
62
+ GAS_SHA256WORD = 12
63
+
64
+ def call(vm)
65
+ input_bytes = vm.instruction.data
66
+ word_count = input_bytes.size.ceil_div(32) / 32
67
+ gas_fee = GAS_SHA256 + word_count * GAS_SHA256WORD
68
+ vm.consume_gas(gas_fee)
69
+ vm.set_output input_bytes.keccak
70
+ end
71
+ end
72
+
73
+ class RIPEMD160
74
+ GAS_RIPEMD160 = 600
75
+ GAS_RIPEMD160WORD = 120
76
+
77
+ def call(vm)
78
+ input_bytes = vm.instruction.data
79
+ word_count = input_bytes.size.ceil_div(32) / 32
80
+ gas_fee = GAS_RIPEMD160 + word_count * GAS_RIPEMD160WORD
81
+ vm.consume_gas(gas_fee)
82
+ vm.set_output Digest::RMD160.digest(input_bytes).pad_zero(32)
83
+ end
84
+ end
85
+
86
+ class Identity
87
+ GAS_IDENTITY = 15
88
+ GAS_IDENTITYWORD = 3
89
+
90
+ def call(vm)
91
+ input_bytes = vm.instruction.data
92
+ word_count = input_bytes.size.ceil_div(32) / 32
93
+ gas_fee = GAS_IDENTITY + word_count * GAS_IDENTITYWORD
94
+ vm.consume_gas(gas_fee)
95
+ computation.output = input_bytes
96
+ end
97
+ end
98
+
99
+
100
+ end
101
+ end
102
+ end
@@ -1,24 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
3
+ # Copyright 2018 Jiang Jinyang <https://justjjy.com>
4
4
  #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
11
8
  #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
9
+ # http://www.apache.org/licenses/LICENSE-2.0
14
10
  #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
22
16
 
23
17
 
24
18
  require 'forwardable'
@@ -31,11 +25,25 @@ module Ciri
31
25
  extend Forwardable
32
26
 
33
27
  def_delegators :@account_db, :set_nonce, :increment_nonce, :set_balance, :add_balance, :touch_account,
34
- :find_account, :delete_account, :account_dead?, :store, :fetch, :set_account_code, :get_account_code
28
+ :find_account, :delete_account, :account_dead?, :store, :fetch,
29
+ :set_account_code, :get_account_code, :account_exist?
35
30
 
36
- def initialize(db, state_root: nil)
31
+ def initialize(db, state_root: nil, chain: nil)
37
32
  @db = db
38
33
  @account_db = DB::AccountDB.new(db, root_hash: state_root)
34
+ @chain = chain
35
+ end
36
+
37
+ # get ancestor hash
38
+ def get_ancestor_hash(current_hash, ancestor_distance)
39
+ if ancestor_distance > 256 || ancestor_distance < 0
40
+ ''.b
41
+ elsif ancestor_distance == 0
42
+ current_hash
43
+ else
44
+ parent_hash = @chain.get_header(current_hash).parent_hash
45
+ get_ancestor_hash(parent_hash, ancestor_distance - 1)
46
+ end
39
47
  end
40
48
 
41
49
  def snapshot
@@ -43,9 +51,8 @@ module Ciri
43
51
  end
44
52
 
45
53
  def revert(snapshot)
46
- state_root, db = snapshot
47
- @db = db
48
- @account_db = DB::AccountDB.new(db, root_hash: state_root)
54
+ state_root, _db = snapshot
55
+ @account_db = DB::AccountDB.new(@db, root_hash: state_root)
49
56
  end
50
57
 
51
58
  def commit(snapshot)