ruby-ethereum 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +40 -0
- data/lib/ethereum.rb +53 -0
- data/lib/ethereum/abi.rb +333 -0
- data/lib/ethereum/abi/contract_translator.rb +174 -0
- data/lib/ethereum/abi/type.rb +117 -0
- data/lib/ethereum/account.rb +72 -0
- data/lib/ethereum/address.rb +60 -0
- data/lib/ethereum/base_convert.rb +53 -0
- data/lib/ethereum/block.rb +1311 -0
- data/lib/ethereum/block_header.rb +211 -0
- data/lib/ethereum/bloom.rb +83 -0
- data/lib/ethereum/cached_block.rb +36 -0
- data/lib/ethereum/chain.rb +400 -0
- data/lib/ethereum/constant.rb +26 -0
- data/lib/ethereum/core_ext/array/safe_slice.rb +18 -0
- data/lib/ethereum/core_ext/module/lru_cache.rb +20 -0
- data/lib/ethereum/core_ext/numeric/denominations.rb +45 -0
- data/lib/ethereum/core_ext/object/truth.rb +47 -0
- data/lib/ethereum/db.rb +6 -0
- data/lib/ethereum/db/base_db.rb +9 -0
- data/lib/ethereum/db/ephem_db.rb +63 -0
- data/lib/ethereum/db/overlay_db.rb +72 -0
- data/lib/ethereum/db/refcount_db.rb +188 -0
- data/lib/ethereum/env.rb +64 -0
- data/lib/ethereum/ethash.rb +78 -0
- data/lib/ethereum/ethash_ruby.rb +38 -0
- data/lib/ethereum/ethash_ruby/cache.rb +47 -0
- data/lib/ethereum/ethash_ruby/hashimoto.rb +75 -0
- data/lib/ethereum/ethash_ruby/utils.rb +53 -0
- data/lib/ethereum/exceptions.rb +28 -0
- data/lib/ethereum/external_call.rb +173 -0
- data/lib/ethereum/fast_rlp.rb +81 -0
- data/lib/ethereum/fast_vm.rb +625 -0
- data/lib/ethereum/fast_vm/call_data.rb +44 -0
- data/lib/ethereum/fast_vm/message.rb +29 -0
- data/lib/ethereum/fast_vm/state.rb +25 -0
- data/lib/ethereum/ffi/openssl.rb +390 -0
- data/lib/ethereum/index.rb +97 -0
- data/lib/ethereum/log.rb +43 -0
- data/lib/ethereum/miner.rb +84 -0
- data/lib/ethereum/opcodes.rb +131 -0
- data/lib/ethereum/private_key.rb +92 -0
- data/lib/ethereum/pruning_trie.rb +28 -0
- data/lib/ethereum/public_key.rb +88 -0
- data/lib/ethereum/receipt.rb +53 -0
- data/lib/ethereum/secp256k1.rb +58 -0
- data/lib/ethereum/secure_trie.rb +49 -0
- data/lib/ethereum/sedes.rb +42 -0
- data/lib/ethereum/special_contract.rb +95 -0
- data/lib/ethereum/spv.rb +79 -0
- data/lib/ethereum/spv/proof.rb +31 -0
- data/lib/ethereum/spv/proof_constructor.rb +19 -0
- data/lib/ethereum/spv/proof_verifier.rb +24 -0
- data/lib/ethereum/tester.rb +14 -0
- data/lib/ethereum/tester/abi_contract.rb +65 -0
- data/lib/ethereum/tester/fixture.rb +31 -0
- data/lib/ethereum/tester/language.rb +30 -0
- data/lib/ethereum/tester/log_recorder.rb +13 -0
- data/lib/ethereum/tester/solidity_wrapper.rb +144 -0
- data/lib/ethereum/tester/state.rb +194 -0
- data/lib/ethereum/transaction.rb +196 -0
- data/lib/ethereum/transient_trie.rb +28 -0
- data/lib/ethereum/trie.rb +549 -0
- data/lib/ethereum/trie/nibble_key.rb +184 -0
- data/lib/ethereum/utils.rb +191 -0
- data/lib/ethereum/version.rb +5 -0
- data/lib/ethereum/vm.rb +606 -0
- data/lib/ethereum/vm/call_data.rb +40 -0
- data/lib/ethereum/vm/message.rb +30 -0
- data/lib/ethereum/vm/state.rb +25 -0
- metadata +284 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module Ethereum
|
6
|
+
module SPV
|
7
|
+
class Proof
|
8
|
+
|
9
|
+
attr :nodes, :exempts
|
10
|
+
|
11
|
+
def initialize(nodes: Set.new, exempts: [])
|
12
|
+
@nodes = nodes
|
13
|
+
@exempts = exempts
|
14
|
+
end
|
15
|
+
|
16
|
+
def decoded_nodes
|
17
|
+
nodes.map {|n| RLP.decode(n) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_node(node)
|
21
|
+
node = FastRLP.encode node
|
22
|
+
nodes.add(node) unless exempts.include?(node)
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_exempt(node)
|
26
|
+
exempts.add FastRLP.encode(node)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module Ethereum
|
6
|
+
module SPV
|
7
|
+
class ProofVerifier < Proof
|
8
|
+
|
9
|
+
def initialize(nodes, exempts: [])
|
10
|
+
nodes = nodes.map {|n| RLP.encode(n) }.to_set
|
11
|
+
super(nodes: nodes, exempts: exempts)
|
12
|
+
end
|
13
|
+
|
14
|
+
def grabbing(node)
|
15
|
+
raise InvalidSPVProof unless nodes.include?(FastRLP.encode(node))
|
16
|
+
end
|
17
|
+
|
18
|
+
def store(node)
|
19
|
+
add_node node.dup
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
require 'ethereum/tester/abi_contract'
|
4
|
+
require 'ethereum/tester/fixture'
|
5
|
+
require 'ethereum/tester/solidity_wrapper'
|
6
|
+
require 'ethereum/tester/language'
|
7
|
+
require 'ethereum/tester/log_recorder'
|
8
|
+
require 'ethereum/tester/state'
|
9
|
+
|
10
|
+
module Ethereum
|
11
|
+
module Tester
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
module Ethereum
|
4
|
+
module Tester
|
5
|
+
class ABIContract
|
6
|
+
|
7
|
+
attr :address, :abi
|
8
|
+
|
9
|
+
def initialize(state, abi, address, listen: true, log_listener: nil)
|
10
|
+
@state = state
|
11
|
+
@abi = abi
|
12
|
+
@address = address
|
13
|
+
|
14
|
+
@translator = ABI::ContractTranslator.new abi
|
15
|
+
|
16
|
+
if listen
|
17
|
+
if log_listener
|
18
|
+
listener = lambda do |log|
|
19
|
+
r = @translator.listen(log, noprint: true)
|
20
|
+
log_listener.call r if r.true?
|
21
|
+
end
|
22
|
+
else
|
23
|
+
listener = ->(log) { @translator.listen(log, noprint: false) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
@translator.function_data.each do |f, _|
|
28
|
+
generate_function f
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def listen(x)
|
33
|
+
@translator.listen x
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def generate_function(f)
|
39
|
+
singleton_class.class_eval <<-EOF
|
40
|
+
def #{f}(*args, **kwargs)
|
41
|
+
sender = kwargs.delete(:sender) || Fixture.keys[0]
|
42
|
+
to = @address
|
43
|
+
value = kwargs.delete(:value) || 0
|
44
|
+
evmdata = @translator.encode('#{f}', args)
|
45
|
+
output = kwargs.delete(:output)
|
46
|
+
|
47
|
+
o = @state._send_tx(sender, to, value, **kwargs.merge(evmdata: evmdata))
|
48
|
+
|
49
|
+
if output == :raw
|
50
|
+
outdata = o[:output]
|
51
|
+
elsif o[:output].false?
|
52
|
+
outdata = nil
|
53
|
+
else
|
54
|
+
outdata = @translator.decode '#{f}', o[:output]
|
55
|
+
outdata = outdata.size == 1 ? outdata[0] : outdata
|
56
|
+
end
|
57
|
+
|
58
|
+
kwargs[:profiling].true? ? o.merge(outdata: outdata) : outdata
|
59
|
+
end
|
60
|
+
EOF
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
module Ethereum
|
4
|
+
module Tester
|
5
|
+
module Fixture
|
6
|
+
|
7
|
+
NUM_ACCOUNTS = 10
|
8
|
+
|
9
|
+
class <<self
|
10
|
+
def keys
|
11
|
+
@keys ||= NUM_ACCOUNTS.times.map {|i| Utils.keccak256(i.to_s) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def accounts
|
15
|
+
@accounts ||= NUM_ACCOUNTS.times.map {|i| PrivateKey.new(keys[i]).to_address }
|
16
|
+
end
|
17
|
+
|
18
|
+
def gas_limit
|
19
|
+
@gas_limit ||= 3141592
|
20
|
+
end
|
21
|
+
attr_writer :gas_limit
|
22
|
+
|
23
|
+
def gas_price
|
24
|
+
@gas_price ||= 1
|
25
|
+
end
|
26
|
+
attr_writer :gas_price
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
module Ethereum
|
4
|
+
module Tester
|
5
|
+
module Language
|
6
|
+
|
7
|
+
class <<self
|
8
|
+
def all
|
9
|
+
return @all if @all
|
10
|
+
|
11
|
+
@all = {
|
12
|
+
serpent: Serpent,
|
13
|
+
solidity: SolidityWrapper.solc_path && SolidityWrapper
|
14
|
+
}
|
15
|
+
|
16
|
+
@all
|
17
|
+
end
|
18
|
+
|
19
|
+
def get(name)
|
20
|
+
all[name]
|
21
|
+
end
|
22
|
+
|
23
|
+
def format_spaces(code)
|
24
|
+
code =~ /\A(\s+)/ ? code.gsub(/^#{$1}/, '') : code
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
module Ethereum
|
4
|
+
module Tester
|
5
|
+
|
6
|
+
module SolidityWrapper
|
7
|
+
|
8
|
+
class CompileError < StandardError; end
|
9
|
+
|
10
|
+
class <<self
|
11
|
+
def split_contracts(code)
|
12
|
+
contracts = []
|
13
|
+
contract = nil
|
14
|
+
|
15
|
+
code.split("\n").each do |line|
|
16
|
+
if line =~ /\Acontract /
|
17
|
+
contracts.push(contract.join("\n")) if contract
|
18
|
+
contract = [line]
|
19
|
+
elsif contract
|
20
|
+
contract.push line
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
contracts.push(contract.join("\n")) if contract
|
25
|
+
|
26
|
+
contracts
|
27
|
+
end
|
28
|
+
|
29
|
+
def contract_names(code)
|
30
|
+
names = []
|
31
|
+
|
32
|
+
split_contracts(code).each do |contract|
|
33
|
+
keyword, name, _ = contract.split(/\s+/, 3)
|
34
|
+
raise AssertError, 'keyword must be contract' unless keyword == 'contract' && !name.empty?
|
35
|
+
names.push name
|
36
|
+
end
|
37
|
+
|
38
|
+
names
|
39
|
+
end
|
40
|
+
|
41
|
+
def combined(code)
|
42
|
+
out = Tempfile.new 'solc_output_'
|
43
|
+
|
44
|
+
pipe = IO.popen([solc_path, '--add-std', '--optimize', '--combined-json', 'abi,bin,devdoc,userdoc'], 'w', [:out, :err] => out)
|
45
|
+
pipe.write code
|
46
|
+
pipe.close_write
|
47
|
+
raise CompileError, 'compilation failed' unless $?.success?
|
48
|
+
|
49
|
+
out.rewind
|
50
|
+
contracts = JSON.parse(out.read)['contracts']
|
51
|
+
|
52
|
+
contracts.each do |name, data|
|
53
|
+
data['abi'] = JSON.parse data['abi']
|
54
|
+
data['devdoc'] = JSON.parse data['devdoc']
|
55
|
+
data['userdoc'] = JSON.parse data['userdoc']
|
56
|
+
end
|
57
|
+
|
58
|
+
names = contract_names code
|
59
|
+
raise AssertError unless names.size <= contracts.size
|
60
|
+
|
61
|
+
names.map {|n| [n, contracts[n]] }
|
62
|
+
ensure
|
63
|
+
out.close
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Returns binary of last contract in code.
|
68
|
+
#
|
69
|
+
def compile(code, contract_name='')
|
70
|
+
sorted_contracts = combined code
|
71
|
+
if contract_name.true?
|
72
|
+
idx = sorted_contracts.map(&:first).index(contract_name)
|
73
|
+
else
|
74
|
+
idx = -1
|
75
|
+
end
|
76
|
+
|
77
|
+
Utils.decode_hex sorted_contracts[idx][1]['bin']
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Returns signature of last contract in code.
|
82
|
+
#
|
83
|
+
def mk_full_signature(code, contract_name='')
|
84
|
+
sorted_contracts = combined code
|
85
|
+
if contract_name.true?
|
86
|
+
idx = sorted_contracts.map(&:first).index(contract_name)
|
87
|
+
else
|
88
|
+
idx = -1
|
89
|
+
end
|
90
|
+
|
91
|
+
sorted_contracts[idx][1]['abi']
|
92
|
+
end
|
93
|
+
|
94
|
+
def compiler_version
|
95
|
+
output = `#{solc_path} --version`.strip
|
96
|
+
output =~ /^Version: ([0-9a-z.-]+)\// ? $1 : nil
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
# Full format as returned by jsonrpc.
|
101
|
+
#
|
102
|
+
def compile_rich(code)
|
103
|
+
combined(code).map do |(name, contract)|
|
104
|
+
[
|
105
|
+
name,
|
106
|
+
{
|
107
|
+
'code' => "0x#{contract['bin']}",
|
108
|
+
'info' => {
|
109
|
+
'abiDefinition' => contract['abi'],
|
110
|
+
'compilerVersion' => compiler_version,
|
111
|
+
'developerDoc' => contract['devdoc'],
|
112
|
+
'language' => 'Solidity',
|
113
|
+
'languageVersion' => '0',
|
114
|
+
'source' => code,
|
115
|
+
'userDoc' => contract['userdoc']
|
116
|
+
}
|
117
|
+
}
|
118
|
+
]
|
119
|
+
end.to_h
|
120
|
+
end
|
121
|
+
|
122
|
+
def solc_path
|
123
|
+
@solc_path ||= which('solc')
|
124
|
+
end
|
125
|
+
|
126
|
+
def solc_path=(v)
|
127
|
+
@solc_path = v
|
128
|
+
end
|
129
|
+
|
130
|
+
def which(cmd)
|
131
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
132
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
133
|
+
exts.each { |ext|
|
134
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
135
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
136
|
+
}
|
137
|
+
end
|
138
|
+
return nil
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# -*- encoding : ascii-8bit -*-
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Ethereum
|
6
|
+
module Tester
|
7
|
+
class State
|
8
|
+
|
9
|
+
TMP_DIR_PREFIX = 'eth-tester-'.freeze
|
10
|
+
|
11
|
+
attr :block, :blocks
|
12
|
+
|
13
|
+
def initialize(num_accounts=Fixture::NUM_ACCOUNTS)
|
14
|
+
@temp_data_dir = Dir.mktmpdir TMP_DIR_PREFIX
|
15
|
+
|
16
|
+
@db = DB::EphemDB.new
|
17
|
+
@env = Env.new @db
|
18
|
+
|
19
|
+
@block = Block.genesis @env, start_alloc: get_start_alloc(num_accounts)
|
20
|
+
@block.timestamp = 1410973349
|
21
|
+
@block.coinbase = Fixture.accounts[0]
|
22
|
+
@block.gas_limit = 10**9
|
23
|
+
|
24
|
+
@blocks = [@block]
|
25
|
+
@last_tx = nil
|
26
|
+
|
27
|
+
ObjectSpace.define_finalizer(self) {|id| FileUtils.rm_rf(@temp_data_dir) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def contract(code, sender: Fixture.keys[0], endowment: 0, language: :serpent, gas: nil)
|
31
|
+
code = Language.format_spaces code
|
32
|
+
opcodes = Language.get(language).compile(code)
|
33
|
+
addr = evm(opcodes, sender: sender, endowment: endowment)
|
34
|
+
raise AssertError, "Contract code empty" if @block.get_code(addr).empty?
|
35
|
+
addr
|
36
|
+
end
|
37
|
+
|
38
|
+
def abi_contract(code, **kwargs)
|
39
|
+
sender = kwargs.delete(:sender) || Fixture.keys[0]
|
40
|
+
endowment = kwargs.delete(:endowment) || 0
|
41
|
+
language = kwargs.delete(:language) || :serpent
|
42
|
+
contract_name = kwargs.delete(:contract_name) || ''
|
43
|
+
gas = kwargs.delete(:gas) || nil
|
44
|
+
log_listener = kwargs.delete(:log_listener) || nil
|
45
|
+
listen = kwargs.delete(:listen) || true
|
46
|
+
|
47
|
+
code = Language.format_spaces code
|
48
|
+
|
49
|
+
if contract_name.true?
|
50
|
+
raise ArgumentError, "language must be solidity when contract name is given" unless language == :solidity
|
51
|
+
cn_args = {contract_name: contract_name}
|
52
|
+
else
|
53
|
+
cn_args = kwargs
|
54
|
+
end
|
55
|
+
|
56
|
+
lang = Language.get language
|
57
|
+
opcodes = lang.compile code, **cn_args
|
58
|
+
addr = evm(opcodes, sender: sender, endowment: endowment, gas: gas)
|
59
|
+
raise AssertError, "Contract code empty" if @block.get_code(addr).empty?
|
60
|
+
|
61
|
+
abi = lang.mk_full_signature(code, **cn_args)
|
62
|
+
ABIContract.new(self, abi, addr, listen: listen, log_listener: log_listener)
|
63
|
+
end
|
64
|
+
|
65
|
+
def evm(opcodes, sender: Fixture.keys[0], endowment: 0, gas: nil)
|
66
|
+
sendnonce = @block.get_nonce PrivateKey.new(sender).to_address
|
67
|
+
|
68
|
+
tx = Transaction.contract sendnonce, Fixture.gas_price, Fixture.gas_limit, endowment, opcodes
|
69
|
+
tx.sign sender
|
70
|
+
tx.startgas = gas if gas
|
71
|
+
|
72
|
+
success, output = @block.apply_transaction tx
|
73
|
+
raise ContractCreationFailed if success.false?
|
74
|
+
|
75
|
+
output
|
76
|
+
end
|
77
|
+
|
78
|
+
def call(*args, **kwargs)
|
79
|
+
raise DeprecatedError, "Call deprecated. Please use the abi_contract mechanism or message(sender, to, value, data) directly, using the ABI module to generate data if needed."
|
80
|
+
end
|
81
|
+
|
82
|
+
def send_tx(*args, **kwargs)
|
83
|
+
_send_tx(*args, **kwargs)[:output]
|
84
|
+
end
|
85
|
+
|
86
|
+
def _send_tx(sender, to, value, evmdata: '', output: nil, funid: nil, abi: nil, profiling: 0)
|
87
|
+
if funid || abi
|
88
|
+
raise ArgumentError, "Send with funid+abi is deprecated. Please use the abi_contract mechanism."
|
89
|
+
end
|
90
|
+
|
91
|
+
t1, g1 = Time.now, @block.gas_used
|
92
|
+
sendnonce = @block.get_nonce PrivateKey.new(sender).to_address
|
93
|
+
tx = Transaction.new(sendnonce, Fixture.gas_price, Fixture.gas_limit, to, value, evmdata)
|
94
|
+
@last_tx = tx
|
95
|
+
tx.sign(sender)
|
96
|
+
|
97
|
+
recorder = profiling > 1 ? LogRecorder.new : nil
|
98
|
+
|
99
|
+
success, output = @block.apply_transaction(tx)
|
100
|
+
raise TransactionFailed if success.false?
|
101
|
+
out = {output: output}
|
102
|
+
|
103
|
+
if profiling > 0
|
104
|
+
zero_bytes = tx.data.count Constant::BYTE_ZERO
|
105
|
+
none_zero_bytes = tx.data.size - zero_bytes
|
106
|
+
intrinsic_gas_used = Opcodes::GTXCOST +
|
107
|
+
Opcodes::GTXDATAZERO * zero_bytes +
|
108
|
+
Opcodes::GTXDATANONZERO * none_zero_bytes
|
109
|
+
t2, g2 = Time.now, @block.gas_used
|
110
|
+
output[:time] = t2 - t1
|
111
|
+
output[:gas] = g2 - g1 - intrinsic_gas_used
|
112
|
+
end
|
113
|
+
|
114
|
+
if profiling > 1
|
115
|
+
# TODO: collect all traced ops use LogRecorder
|
116
|
+
end
|
117
|
+
|
118
|
+
out
|
119
|
+
end
|
120
|
+
|
121
|
+
def profile(*args, **kwargs)
|
122
|
+
kwargs[:profiling] = true
|
123
|
+
_send_tx(*args, **kwargs)
|
124
|
+
end
|
125
|
+
|
126
|
+
def mkspv(sender, to, value, data: [], funid: nil, abi: nil)
|
127
|
+
sendnonce = @block.get_nonce PrivateKey.new(sender).to_address
|
128
|
+
evmdata = funid ? Serpent.encode_abi(funid, *abi) : Serpent.encode_datalist(*data)
|
129
|
+
|
130
|
+
tx = Transaction.new(sendnonce, Fixture.gas_price, Fixture.gas_limit, to, value, evmdata)
|
131
|
+
@last_tx = tx
|
132
|
+
tx.sign(sender)
|
133
|
+
|
134
|
+
SPV.make_transaction_proof(@block, tx)
|
135
|
+
end
|
136
|
+
|
137
|
+
def verifyspv(sender, to, value, data: [], funid: nil, abi: nil, proof: [])
|
138
|
+
sendnonce = @block.get_nonce PrivateKey.new(sender).to_address
|
139
|
+
evmdata = funid ? Serpent.encode_abi(funid, *abi) : Serpent.encode_datalist(*data)
|
140
|
+
|
141
|
+
tx = Transaction.new(sendnonce, Fixture.gas_price, Fixture.gas_limit, to, value, evmdata)
|
142
|
+
@last_tx = tx
|
143
|
+
tx.sign(sender)
|
144
|
+
|
145
|
+
SPV.verify_transaction_proof(@block, tx, proof)
|
146
|
+
end
|
147
|
+
|
148
|
+
def trace(sender, to, value, data=[])
|
149
|
+
recorder = LogRecorder.new
|
150
|
+
send_tx sender, to, value, data
|
151
|
+
recorder.pop_records # TODO: implement recorder
|
152
|
+
end
|
153
|
+
|
154
|
+
def mine(n=1, coinbase: Fixture.accounts[0])
|
155
|
+
n.times do |i|
|
156
|
+
@block.finalize
|
157
|
+
@block.commit_state
|
158
|
+
|
159
|
+
@db.put @block.full_hash, RLP.encode(@block)
|
160
|
+
|
161
|
+
t = @block.timestamp + 6 + rand(12)
|
162
|
+
x = Block.build_from_parent @block, coinbase, timestamp: t
|
163
|
+
@block = x
|
164
|
+
|
165
|
+
@blocks.push @block
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def snapshot
|
170
|
+
RLP.encode @block
|
171
|
+
end
|
172
|
+
|
173
|
+
def revert(data)
|
174
|
+
@block = RLP.decode data, sedes: Block, env: @env
|
175
|
+
|
176
|
+
@block.make_mutable!
|
177
|
+
@block._cached_rlp = nil
|
178
|
+
|
179
|
+
@block.header.make_mutable!
|
180
|
+
@block.header._cached_rlp = nil
|
181
|
+
end
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
def get_start_alloc(num_accounts)
|
186
|
+
o = {}
|
187
|
+
num_accounts.times {|i| o[Fixture.accounts[i]] = {wei: 10**24} }
|
188
|
+
(1...5).each {|i| o[Utils.int_to_addr(i)] = {wei: 1} }
|
189
|
+
o
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|