ciri 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rspec +0 -1
- data/Gemfile.lock +11 -7
- data/LICENSE.txt +201 -21
- data/README.md +78 -25
- data/Rakefile +45 -17
- data/bin/bundle +105 -0
- data/bin/htmldiff +29 -0
- data/bin/ldiff +29 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/ciri-crypto/.gitignore +11 -0
- data/ciri-crypto/.rspec +3 -0
- data/ciri-crypto/.travis.yml +5 -0
- data/ciri-crypto/CODE_OF_CONDUCT.md +74 -0
- data/ciri-crypto/Gemfile +6 -0
- data/ciri-crypto/Gemfile.lock +43 -0
- data/ciri-crypto/LICENSE.txt +201 -0
- data/ciri-crypto/README.md +58 -0
- data/ciri-crypto/Rakefile +6 -0
- data/ciri-crypto/bin/console +14 -0
- data/ciri-crypto/bin/setup +8 -0
- data/ciri-crypto/ciri-crypto.gemspec +40 -0
- data/ciri-crypto/lib/ciri/crypto/errors.rb +29 -0
- data/ciri-crypto/lib/ciri/crypto/signature.rb +71 -0
- data/ciri-crypto/lib/ciri/crypto/version.rb +5 -0
- data/{lib → ciri-crypto/lib}/ciri/crypto.rb +16 -69
- data/ciri-crypto/spec/ciri/crypto_spec.rb +56 -0
- data/ciri-crypto/spec/spec_helper.rb +14 -0
- data/ciri-rlp/Gemfile.lock +5 -5
- data/ciri-rlp/LICENSE.txt +201 -21
- data/ciri-rlp/README.md +1 -1
- data/ciri-rlp/ciri-rlp.gemspec +3 -3
- data/ciri-rlp/lib/ciri/rlp/decode.rb +10 -16
- data/ciri-rlp/lib/ciri/rlp/encode.rb +10 -16
- data/ciri-rlp/lib/ciri/rlp/serializable.rb +10 -16
- data/ciri-rlp/lib/ciri/rlp.rb +10 -16
- data/ciri-rlp/spec/ciri/fixture_spec.rb +10 -16
- data/ciri-rlp/spec/ciri/rlp/serializable_spec.rb +10 -16
- data/ciri-utils/Gemfile.lock +4 -4
- data/ciri-utils/LICENSE.txt +201 -21
- data/ciri-utils/README.md +1 -1
- data/ciri-utils/ciri-utils.gemspec +2 -2
- data/ciri-utils/lib/ciri/utils/logger.rb +10 -16
- data/ciri-utils/lib/ciri/utils/number.rb +10 -16
- data/ciri-utils/lib/ciri/utils/version.rb +1 -1
- data/ciri-utils/lib/ciri/utils.rb +3 -3
- data/ciri.gemspec +4 -3
- data/docker/{Base → Dockerfile} +9 -3
- data/lib/ciri/actor.rb +10 -16
- data/lib/ciri/bloom_filter.rb +11 -17
- data/lib/ciri/chain/block.rb +10 -16
- data/lib/ciri/chain/header.rb +12 -18
- data/lib/ciri/chain/header_chain.rb +8 -22
- data/lib/ciri/chain/transaction.rb +38 -33
- data/lib/ciri/chain.rb +27 -26
- data/lib/ciri/core_ext.rb +61 -0
- data/lib/ciri/db/account_db.rb +25 -21
- data/lib/ciri/db/backend/memory.rb +10 -16
- data/lib/ciri/db/backend/rocks.rb +10 -16
- data/lib/ciri/db/backend/rocks_db.rb +10 -16
- data/lib/ciri/devp2p/peer.rb +10 -16
- data/lib/ciri/devp2p/protocol.rb +10 -16
- data/lib/ciri/devp2p/protocol_io.rb +10 -16
- data/lib/ciri/devp2p/rlpx/connection.rb +10 -16
- data/lib/ciri/devp2p/rlpx/encryption_handshake.rb +13 -19
- data/lib/ciri/devp2p/rlpx/error.rb +10 -16
- data/lib/ciri/devp2p/rlpx/frame_io.rb +10 -16
- data/lib/ciri/devp2p/rlpx/message.rb +10 -16
- data/lib/ciri/devp2p/rlpx/node.rb +10 -16
- data/lib/ciri/devp2p/rlpx/protocol_handshake.rb +10 -16
- data/lib/ciri/devp2p/rlpx/protocol_messages.rb +10 -16
- data/lib/ciri/devp2p/rlpx/secrets.rb +10 -16
- data/lib/ciri/devp2p/rlpx.rb +10 -16
- data/lib/ciri/devp2p/server.rb +10 -16
- data/lib/ciri/eth/peer.rb +10 -16
- data/lib/ciri/eth/protocol_manage.rb +10 -16
- data/lib/ciri/eth/protocol_messages.rb +10 -16
- data/lib/ciri/eth/synchronizer.rb +10 -16
- data/lib/ciri/eth.rb +10 -16
- data/lib/ciri/ethash.rb +10 -16
- data/lib/ciri/evm/block_info.rb +25 -17
- data/lib/ciri/evm/errors.rb +13 -16
- data/lib/ciri/evm/execution_context.rb +136 -0
- data/lib/ciri/evm/instruction.rb +17 -24
- data/lib/ciri/evm/log_entry.rb +12 -18
- data/lib/ciri/evm/machine_state.rb +28 -33
- data/lib/ciri/evm/op.rb +52 -89
- data/lib/ciri/evm/op_call.rb +114 -0
- data/lib/ciri/evm/precompile_contract.rb +102 -0
- data/lib/ciri/evm/state.rb +28 -21
- data/lib/ciri/evm/sub_state.rb +18 -24
- data/lib/ciri/evm/vm.rb +128 -190
- data/lib/ciri/evm.rb +77 -85
- data/lib/ciri/forks/base.rb +28 -16
- data/lib/ciri/forks/byzantium.rb +43 -0
- data/lib/ciri/forks/config.rb +36 -0
- data/lib/ciri/forks/frontier/cost.rb +42 -33
- data/lib/ciri/forks/frontier.rb +47 -18
- data/lib/ciri/forks/homestead/cost.rb +195 -0
- data/lib/ciri/forks/homestead.rb +46 -0
- data/lib/ciri/forks.rb +12 -22
- data/lib/ciri/key.rb +14 -3
- data/lib/ciri/pow.rb +11 -17
- data/lib/ciri/rlp/decode.rb +10 -16
- data/lib/ciri/rlp/encode.rb +10 -16
- data/lib/ciri/rlp/serializable.rb +10 -16
- data/lib/ciri/serialize.rb +14 -17
- data/lib/ciri/trie/nibbles.rb +10 -16
- data/lib/ciri/trie/nodes.rb +12 -17
- data/lib/ciri/trie.rb +12 -18
- data/lib/ciri/types/account.rb +15 -17
- data/lib/ciri/types/address.rb +11 -17
- data/lib/ciri/types/errors.rb +10 -16
- data/lib/ciri/types/receipt.rb +12 -18
- data/lib/ciri/types/uint.rb +79 -0
- data/lib/ciri/version.rb +1 -1
- data/lib/ciri.rb +10 -16
- metadata +54 -10
- data/lib/ciri/types/number.rb +0 -73
@@ -1,26 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright
|
3
|
+
# Copyright 2018 Jiang Jinyang <https://justjjy.com>
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
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
|
-
#
|
13
|
-
# all copies or substantial portions of the Software.
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
10
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
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 :
|
34
|
-
attr_accessor :pc, :output, :memory_item
|
29
|
+
attr_reader :memory, :stack
|
35
30
|
|
36
|
-
def initialize(
|
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 && (
|
93
|
-
|
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
|
3
|
+
# Copyright 2018 Jiang Jinyang <https://justjjy.com>
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
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
|
-
#
|
13
|
-
# all copies or substantial portions of the Software.
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
10
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
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
|
-
|
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
|
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
|
-
|
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.
|
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
|
-
|
437
|
-
vm.
|
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
|
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
|
-
|
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
|
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
|
-
|
524
|
-
|
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
|
data/lib/ciri/evm/state.rb
CHANGED
@@ -1,24 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright
|
3
|
+
# Copyright 2018 Jiang Jinyang <https://justjjy.com>
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
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
|
-
#
|
13
|
-
# all copies or substantial portions of the Software.
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
10
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
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,
|
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,
|
47
|
-
@
|
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)
|