diff --git a/fixtures b/fixtures index 862b4e3..289b3e4 160000 --- a/fixtures +++ b/fixtures @@ -1 +1 @@ -Subproject commit 862b4e3d4a9a7141af1b4aaf7dfe228a6a294614 +Subproject commit 289b3e4524786618c7ec253b516bc8e76350f947 diff --git a/lib/ethereum/block.rb b/lib/ethereum/block.rb index 1740060..84ea5a9 100644 --- a/lib/ethereum/block.rb +++ b/lib/ethereum/block.rb @@ -27,7 +27,7 @@ class Block def_delegators :header, *HeaderGetters, *HeaderSetters attr :env, :db, :config - attr_accessor :state, :transactions, :receipts, :refunds, :suicides, :ether_delta, :ancestor_hashes, :logs, :log_listeners + attr_accessor :state, :transactions, :receipts, :refunds, :suicides, :touched, :ether_delta, :ancestor_hashes, :logs, :log_listeners class <= config[:"#{name}_fork_blknum"] + end + def add_listener(l) log_listeners.push l end @@ -396,6 +401,15 @@ def add_refund(x) self.refunds += x end + def add_touched(addr, gas=nil) + self.touched[addr] ||= 0 + self.touched[addr] += gas if gas + end + + def add_suicide(addr) + self.suicides.push addr + end + ## # Add a transaction to the transaction trie. # @@ -459,8 +473,8 @@ def apply_transaction(tx) self.refunds = 0 end - delta_balance tx.sender, tx.gasprice * gas_remained - delta_balance coinbase, tx.gasprice * gas_used + apply_tx_refund tx.sender, gas_remained, tx.gasprice + apply_tx_reward coinbase, gas_used, tx.gasprice self.gas_used += gas_used output = tx.to.true? ? Utils.int_array_to_bytes(data) : data @@ -469,7 +483,7 @@ def apply_transaction(tx) logger.debug "TX FAILED", reason: 'out of gas', startgas: tx.startgas, gas_remained: gas_remained self.gas_used += tx.startgas - delta_balance coinbase, tx.gasprice*tx.startgas + apply_tx_reward coinbase, tx.startgas, tx.gasprice output = Constant::BYTE_EMPTY success = 0 @@ -484,6 +498,20 @@ def apply_transaction(tx) end self.suicides = [] + if post_hardfork?(:spurious_dragon) + touched.each do |addr, gas| + if account_is_empty(addr) + # revert GCALLNEWACCOUNT cost first + if gas > 0 && tx.gasprice > 0 + apply_tx_refund tx.sender, gas, tx.gasprice + apply_tx_reward coinbase, -gas, tx.gasprice + end + del_account addr + end + end + end + self.touched = {} + add_transaction_to_list tx self.logs = [] @@ -707,6 +735,13 @@ def account_exists(address) @state[address].size > 0 || @caches[:all].has_key?(address) end + ## + # Returns true when the account is either empty or non-exist. + # + def account_is_empty(address) + get_balance(address) == 0 && get_code(address) == Constant::BYTE_EMPTY && get_nonce(address) == 0 + end + def add_log(log) logs.push log log_listeners.each {|l| l.call log } @@ -1352,5 +1387,17 @@ def mk_transaction_receipt(tx) end end + def apply_tx_refund(sender, remained, gasprice) + delta_balance sender, gasprice*remained + end + + def apply_tx_reward(coinbase, used, gasprice) + amount = gasprice * used + delta_balance coinbase, amount + if post_hardfork?(:spurious_dragon) + add_touched coinbase if amount == 0 + end + end + end end diff --git a/lib/ethereum/constant.rb b/lib/ethereum/constant.rb index c4a6323..a4877c8 100644 --- a/lib/ethereum/constant.rb +++ b/lib/ethereum/constant.rb @@ -24,5 +24,7 @@ module Constant PRIVKEY_ZERO = ("\x00"*32).freeze PRIVKEY_ZERO_HEX = ('0'*64).freeze + CONTRACT_CODE_SIZE_LIMIT = 0x6000 + end end diff --git a/lib/ethereum/env.rb b/lib/ethereum/env.rb index f9ec3e0..abcae70 100644 --- a/lib/ethereum/env.rb +++ b/lib/ethereum/env.rb @@ -64,7 +64,7 @@ class Env dao_withdrawer: Utils.normalize_address('0xbf4ed7b27f1d666546e30d74d50d173d20bca754'), anti_dos_fork_blknum: 2457000, - clearing_fork_blknum: 2**100 + spurious_dragon_fork_blknum: 2675000 }.freeze attr :db, :config, :global_config diff --git a/lib/ethereum/external_call.rb b/lib/ethereum/external_call.rb index 4376b36..ba020bc 100644 --- a/lib/ethereum/external_call.rb +++ b/lib/ethereum/external_call.rb @@ -15,7 +15,8 @@ class ExternalCall def_delegators :@block, :get_code, :set_code, :get_balance, :set_balance, :delta_balance, :get_nonce, :set_nonce, :increment_nonce, :get_storage_data, :set_storage_data, :get_storage_bytes, :reset_storage, - :add_refund, :account_exists, :snapshot, :revert, :transfer_value + :add_refund, :add_touched, :add_suicide, :account_exists, :account_is_empty, + :snapshot, :revert, :transfer_value, :post_hardfork? def initialize(block, tx) @block = block @@ -26,12 +27,8 @@ def log_storage(x) @block.account_to_dict(x)[:storage] end - def add_suicide(x) - @block.suicides.push x - end - def block_hash(x) - if post_metropolis_hardfork + if post_hardfork?(:metropolis) get_storage_data @block.config[:metropolis_blockhash_store], x else d = @block.number - x @@ -76,25 +73,13 @@ def tx_gasprice @tx.gasprice end - def post_homestead_hardfork - @block.number >= @block.config[:homestead_fork_blknum] - end - - def post_anti_dos_hardfork - @block.number >= @block.config[:anti_dos_fork_blknum] - end - - def post_metropolis_hardfork - @block.number >= @block.config[:metropolis_fork_blknum] - end - def create(msg) log_msg.debug 'CONTRACT CREATION' sender = Utils.normalize_address(msg.sender, allow_blank: true) code = msg.data.extract_all - if post_metropolis_hardfork + if post_hardfork?(:metropolis) msg.to = Utils.mk_metropolis_contract_address msg.sender, code if get_code(msg.to) n1 = get_nonce msg.to @@ -114,7 +99,7 @@ def create(msg) balance = get_balance(msg.to) if balance > 0 set_balance msg.to, balance - set_nonce msg.to, 0 + set_nonce msg.to, @block.config[:account_initial_nonce] set_code msg.to, Constant::BYTE_EMPTY reset_storage msg.to end @@ -123,19 +108,21 @@ def create(msg) msg.data = VM::CallData.new [], 0, 0 snapshot = self.snapshot + increment_nonce msg.to if post_hardfork?(:spurious_dragon) res, gas, dat = apply_msg msg, code if res.true? return 1, gas, msg.to if dat.empty? - gcost = dat.size * Opcodes::GCONTRACTBYTE + gcost = dat.size > Constant::CONTRACT_CODE_SIZE_LIMIT ? + Constant::UINT_MAX : dat.size * Opcodes::GCONTRACTBYTE if gas >= gcost gas -= gcost else dat = [] log_msg.debug "CONTRACT CREATION OOG", have: gas, want: gcost, block_number: @block.number - if post_homestead_hardfork + if post_hardfork?(:homestead) revert snapshot return 0, 0, Constant::BYTE_EMPTY end @@ -144,6 +131,7 @@ def create(msg) set_code msg.to, Utils.int_array_to_bytes(dat) return 1, gas, msg.to else + revert snapshot if post_hardfork?(:homestead) return 0, gas, Constant::BYTE_EMPTY end end @@ -190,6 +178,10 @@ def apply_msg(msg, code=nil) revert snapshot end + if post_hardfork?(:spurious_dragon) + add_touched msg.to if msg.value == 0 + end + return res, gas, dat end diff --git a/lib/ethereum/opcodes.rb b/lib/ethereum/opcodes.rb index 58b7fa5..2defa2b 100644 --- a/lib/ethereum/opcodes.rb +++ b/lib/ethereum/opcodes.rb @@ -134,5 +134,7 @@ class Opcodes CALL_CHILD_LIMIT_NUM = 63 CALL_CHILD_LIMIT_DENOM = 64 SUICIDE_SUPPLEMENTAL_GAS = 5000 + GEXPONENTBYTE_SUPPLEMENTAL_GAS = 40 + end end diff --git a/lib/ethereum/secp256k1.rb b/lib/ethereum/secp256k1.rb index a51f9e0..2681196 100644 --- a/lib/ethereum/secp256k1.rb +++ b/lib/ethereum/secp256k1.rb @@ -29,7 +29,7 @@ def recoverable_sign(msg, privkey) pk = ::Secp256k1::PrivateKey.new privkey: privkey, raw: true signature = pk.ecdsa_recoverable_serialize pk.ecdsa_sign_recoverable(msg, raw: true) - v = signature[1] + 27 + v = signature[1] r = Utils.big_endian_to_int signature[0][0,32] s = Utils.big_endian_to_int signature[0][32,32] @@ -49,7 +49,7 @@ def signature_verify(msg, vrs, pubkey) def recover_pubkey(msg, vrs, compressed: false) pk = ::Secp256k1::PublicKey.new(flags: ::Secp256k1::ALL_FLAGS) sig = Utils.zpad_int(vrs[1]) + Utils.zpad_int(vrs[2]) - recsig = pk.ecdsa_recoverable_deserialize(sig, vrs[0]-27) + recsig = pk.ecdsa_recoverable_deserialize(sig, vrs[0]) pk.public_key = pk.ecdsa_recover msg, recsig, raw: true pk.serialize compressed: compressed end diff --git a/lib/ethereum/special_contract.rb b/lib/ethereum/special_contract.rb index 8edcb1a..e6e587c 100644 --- a/lib/ethereum/special_contract.rb +++ b/lib/ethereum/special_contract.rb @@ -16,7 +16,7 @@ def call(ext, msg) r = msg.data.extract32(64) s = msg.data.extract32(96) - if r >= Secp256k1::N || s >= Secp256k1::N || v < 27 || v > 28 + if r >= Secp256k1::N || s >= Secp256k1::N || v < Transaction::V_MIN || v > Transaction::V_MAX return 1, msg.gas - gas_cost, [] end @@ -27,7 +27,7 @@ def call(ext, msg) pub = nil begin - pub = Secp256k1.recover_pubkey(message_hash, [v,r,s]) + pub = Secp256k1.recover_pubkey(message_hash, [Transaction.decode_v(v),r,s]) rescue return 1, msg.gas - gas_cost, [] end diff --git a/lib/ethereum/tester/solidity_wrapper.rb b/lib/ethereum/tester/solidity_wrapper.rb index 2afaf18..244088f 100644 --- a/lib/ethereum/tester/solidity_wrapper.rb +++ b/lib/ethereum/tester/solidity_wrapper.rb @@ -205,7 +205,7 @@ def solidity_library_symbol(library_name) # Change the bytecode to use the given library address. # # @param hex_code [String] The bytecode encoded in hex. - # @param library_name [String] The library that will be resolved. + # @param library_symbol [String] The library that will be resolved. # @param library_address [String] The address of the library. # # @return [String] The bytecode encoded in hex with the library diff --git a/lib/ethereum/transaction.rb b/lib/ethereum/transaction.rb index 94f4243..ca0ef86 100644 --- a/lib/ethereum/transaction.rb +++ b/lib/ethereum/transaction.rb @@ -40,6 +40,14 @@ class Transaction s: big_endian_int ) + V_MIN = 27 + V_MAX = 28 + + EIP155_V_OFFSET = 35 + EIP155_CHAIN_ID = 1 + EIP155_V_MIN = EIP155_V_OFFSET + 2 * EIP155_CHAIN_ID + EIP155_V_MAX = EIP155_V_MIN + 1 + class < 0 - raise InvalidTransaction, "Invalid signature values!" if r >= Secp256k1::N || s >= Secp256k1::N || v < 27 || v > 28 || r == 0 || s == 0 + v = Transaction.decode_v(self.v) + if v + raise InvalidTransaction, "Invalid signature values!" if r >= Secp256k1::N || s >= Secp256k1::N || v > 1 || r == 0 || s == 0 logger.debug "recovering sender" - rlpdata = RLP.encode(self, sedes: UnsignedTransaction) - rawhash = Utils.keccak256 rlpdata + rawhash = Utils.keccak256 signing_data(:verify) pub = nil begin @@ -98,14 +126,14 @@ def sender=(v) # # A potentially already existing signature would be override. # - def sign(key) + def sign(key, eip155=false) raise InvalidTransaction, "Zero privkey cannot sign" if [0, '', Constant::PRIVKEY_ZERO, Constant::PRIVKEY_ZERO_HEX].include?(key) - rawhash = Utils.keccak256 RLP.encode(self, sedes: UnsignedTransaction) + rawhash = Utils.keccak256 signing_data(:sign) key = PrivateKey.new(key).encode(:bin) vrs = Secp256k1.recoverable_sign rawhash, key - self.v = vrs[0] + self.v = Transaction.encode_v(vrs[0], eip155) self.r = vrs[1] self.s = vrs[2] @@ -124,6 +152,29 @@ def check_low_s raise InvalidTransaction, "Invalid signature S value!" if s > Secp256k1::N/2 || s == 0 end + def signing_data(mode) + case mode + when :sign + if v == 0 # use encoding rules before EIP155 + RLP.encode(self, sedes: UnsignedTransaction) + elsif v == EIP155_CHAIN_ID && r == 0 && s == 0 # after EIP155, v is chain_id >= 1 + RLP.encode(self, sedes: Transaction) + else + raise InvalidTransaction, "invalid signature" + end + when :verify + if v == V_MIN || v == V_MAX # encoded v before EIP155 + RLP.encode(self, sedes: UnsignedTransaction) + elsif v == EIP155_V_MIN || v == EIP155_V_MAX # after EIP155, v with chain_id encoded in it + values = UnsignedTransaction.serializable_fields.keys.map {|k| send k } + values += [EIP155_CHAIN_ID, 0, 0] + RLP.encode(values, sedes: Transaction.serializable_sedes) + end + else + raise InvalidTransaction, "invalid signature" + end + end + def full_hash Utils.keccak256_rlp self end diff --git a/lib/ethereum/utils.rb b/lib/ethereum/utils.rb index ad4cd6f..500f930 100644 --- a/lib/ethereum/utils.rb +++ b/lib/ethereum/utils.rb @@ -232,5 +232,30 @@ def child_dao_list main + child_daos + child_extra_balances end + def debug_by_step(ext, msg, s, op, in_args, out_args, fee, opcode, pushval) + indent = (msg.depth+1) * 5 + prefix1 = '-' * indent + prefix2 = ' ' * indent + prefix2[-1] = '|' + + puts "#{prefix1} ##{s.pc} 0x#{opcode.to_s(16)} #{s.gas} [#{msg.depth}]" + puts "#{prefix2} MEM: #{s.memory.map {|byte| byte.to_s(16)}.join(' ')}" + puts "#{prefix2} STACK: #{s.stack.map {|byte| '0x' + Utils.encode_hex(Utils.int_to_big_endian(byte)) }.join(' ')}" + case op + when /^PUSH/ + puts "#{prefix2} #{op} 0x#{Utils.encode_hex(Utils.int_to_big_endian(pushval))} (#{pushval})" + when /^CREATE/ + sender = Utils.normalize_address(msg.to, allow_blank: true) + msg_to_nonce = ext.get_nonce(msg.to) + nonce = Utils.encode_int(ext.tx_origin == msg.to ? msg_to_nonce-1 : msg_to_nonce) + puts "#{prefix2} #{op} 0x#{Utils.encode_hex(Utils.mk_contract_address(sender, nonce))}" + when /^INVALID/ + # do nothing + else + puts "#{prefix2} #{op}" + end + STDIN.gets + end + end end diff --git a/lib/ethereum/vm.rb b/lib/ethereum/vm.rb index f3edf80..7e044fa 100644 --- a/lib/ethereum/vm.rb +++ b/lib/ethereum/vm.rb @@ -37,6 +37,7 @@ def execute(ext, msg, code) return peaceful_exit('CODE OUT OF RANGE', s.gas, []) if s.pc >= processed_code.size op, in_args, out_args, fee, opcode, pushval = processed_code[s.pc] + #Utils.debug_by_step(ext, msg, s, op, in_args, out_args, fee, opcode, pushval) return vm_exception('OUT OF GAS') if fee > s.gas return vm_exception('INSUFFICIENT STACK', op: op, needed: in_args, available: s.stack.size) if in_args > s.stack.size @@ -133,7 +134,8 @@ def execute(ext, msg, code) # fee for exponent is dependent on its bytes # calc n bytes to represent exponent nbytes = Utils.encode_int(exponent).size - expfee = nbytes * Opcodes::GEXPONENTBYTE + expprice = Opcodes::GEXPONENTBYTE + (ext.post_hardfork?(:spurious_dragon) ? 1 : 0) * Opcodes::GEXPONENTBYTE_SUPPLEMENTAL_GAS + expfee = nbytes * expprice if s.gas < expfee s.gas = 0 return vm_exception('OOG EXPONENT') @@ -210,7 +212,7 @@ def execute(ext, msg, code) when :ADDRESS stk.push Utils.coerce_to_int(msg.to) when :BALANCE - if ext.post_anti_dos_hardfork + if ext.post_hardfork?(:anti_dos) return vm_exception('OUT OF GAS') unless eat_gas(s, Opcodes::BALANCE_SUPPLEMENTAL_GAS) end s0 = stk.pop @@ -251,14 +253,14 @@ def execute(ext, msg, code) when :GASPRICE stk.push ext.tx_gasprice when :EXTCODESIZE - if ext.post_anti_dos_hardfork + if ext.post_hardfork?(:anti_dos) return vm_exception('OUT OF GAS') unless eat_gas(s, Opcodes::EXTCODELOAD_SUPPLEMENTAL_GAS) end addr = stk.pop addr = Utils.coerce_addr_to_hex(addr % 2**160) stk.push (ext.get_code(addr) || Constant::BYTE_EMPTY).size when :EXTCODECOPY - if ext.post_anti_dos_hardfork + if ext.post_hardfork?(:anti_dos) return vm_exception('OUT OF GAS') unless eat_gas(s, Opcodes::EXTCODELOAD_SUPPLEMENTAL_GAS) end addr, mstart, cstart, size = stk.pop, stk.pop, stk.pop, stk.pop @@ -316,7 +318,7 @@ def execute(ext, msg, code) return vm_exception('OOG EXTENDING MEMORY') unless mem_extend(mem, s, s0, 1) mem[s0] = s1 % 256 when :SLOAD - if ext.post_anti_dos_hardfork + if ext.post_hardfork?(:anti_dos) return vm_exception('OUT OF GAS') unless eat_gas(s, Opcodes::SLOAD_SUPPLEMENTAL_GAS) end s0 = stk.pop @@ -408,9 +410,7 @@ def execute(ext, msg, code) cd = CallData.new mem, mstart, msz ingas = s.gas - if ext.post_anti_dos_hardfork - ingas = max_call_gas(ingas) - end + ingas = max_call_gas(ingas) if ext.post_hardfork?(:anti_dos) create_msg = Message.new(msg.to, Constant::BYTE_EMPTY, value, ingas, cd, depth: msg.depth+1) o, gas, addr = ext.create create_msg @@ -432,13 +432,25 @@ def execute(ext, msg, code) return vm_exception('OOG EXTENDING MEMORY') unless mem_extend(mem, s, memout_start, memout_sz) to = Utils.zpad_int(to)[12..-1] # last 20 bytes - extra_gas = (ext.account_exists(to) ? 0 : 1) * Opcodes::GCALLNEWACCOUNT + - (value > 0 ? 1 : 0) * Opcodes::GCALLVALUETRANSFER + - (ext.post_anti_dos_hardfork ? 1 : 0) * Opcodes::CALL_SUPPLEMENTAL_GAS - if ext.post_anti_dos_hardfork + extra_gas = (value > 0 ? 1 : 0) * Opcodes::GCALLVALUETRANSFER + new_account_charge = 0 + if ext.post_hardfork?(:spurious_dragon) + if ext.account_is_empty(to) && value > 0 + new_account_charge = Opcodes::GCALLNEWACCOUNT + extra_gas += new_account_charge + end + extra_gas += Opcodes::CALL_SUPPLEMENTAL_GAS + return vm_exception('OUT OF GAS', needed: extra_gas) if s.gas < extra_gas + gas = [gas, max_call_gas(s.gas-extra_gas)].min + elsif ext.post_hardfork?(:anti_dos) + new_account_charge = (ext.account_exists(to) ? 0 : 1) * Opcodes::GCALLNEWACCOUNT + extra_gas += new_account_charge + extra_gas += Opcodes::CALL_SUPPLEMENTAL_GAS return vm_exception('OUT OF GAS', needed: extra_gas) if s.gas < extra_gas gas = [gas, max_call_gas(s.gas-extra_gas)].min else + new_account_charge = (ext.account_exists(to) ? 0 : 1) * Opcodes::GCALLNEWACCOUNT + extra_gas += new_account_charge return vm_exception('OUT OF GAS', needed: gas+extra_gas) if s.gas < gas+extra_gas end @@ -459,6 +471,10 @@ def execute(ext, msg, code) [data.size, memout_sz].min.times do |i| mem[memout_start+i] = data[i] end + + if ext.post_hardfork?(:spurious_dragon) + ext.add_touched to, new_account_charge if new_account_charge > 0 + end end else s.gas -= (total_gas - submsg_gas) @@ -478,8 +494,8 @@ def execute(ext, msg, code) return vm_exception('OOG EXTENDING MEMORY') unless mem_extend(mem, s, memout_start, memout_sz) extra_gas = (value > 0 ? 1 : 0) * Opcodes::GCALLVALUETRANSFER + - (ext.post_anti_dos_hardfork ? 1 : 0) * Opcodes::CALL_SUPPLEMENTAL_GAS - if ext.post_anti_dos_hardfork + (ext.post_hardfork?(:anti_dos) ? 1 : 0) * Opcodes::CALL_SUPPLEMENTAL_GAS + if ext.post_hardfork?(:anti_dos) return vm_exception('OUT OF GAS', needed: extra_gas) if s.gas < extra_gas gas = [gas, max_call_gas(s.gas-extra_gas)].min else @@ -494,7 +510,7 @@ def execute(ext, msg, code) to = Utils.zpad_int(to)[12..-1] # last 20 bytes cd = CallData.new mem, memin_start, memin_sz - if ext.post_homestead_hardfork && op == :DELEGATECALL + if ext.post_hardfork?(:homestead) && op == :DELEGATECALL call_msg = Message.new(msg.sender, msg.to, msg.value, submsg_gas, cd, depth: msg.depth+1, code_address: to, transfers_value: false) elsif op == :DELEGATECALL return vm_exception('OPCODE INACTIVE') @@ -524,13 +540,26 @@ def execute(ext, msg, code) s0 = stk.pop to = Utils.zpad_int(s0)[12..-1] # last 20 bytes - if ext.post_anti_dos_hardfork + xfer = nil + if ext.post_hardfork?(:spurious_dragon) + extra_gas = Opcodes::SUICIDE_SUPPLEMENTAL_GAS + return vm_exception('OUT OF GAS') unless eat_gas(s, extra_gas) + + # check balance after check SUICIDE_SUPPLEMENTAL_GAS to avoid DoS + xfer = ext.get_balance(msg.to) + if xfer > 0 && ext.account_is_empty(to) + extra_gas += Opcodes::GCALLNEWACCOUNT # no use, just to keep consistency + return vm_exception('OUT OF GAS') unless eat_gas(s, Opcodes::GCALLNEWACCOUNT) + end + + ext.add_touched(to) if xfer == 0 + elsif ext.post_hardfork?(:anti_dos) extra_gas = Opcodes::SUICIDE_SUPPLEMENTAL_GAS + (ext.account_exists(to) ? 0 : 1) * Opcodes::GCALLNEWACCOUNT return vm_exception('OUT OF GAS') unless eat_gas(s, extra_gas) end - xfer = ext.get_balance(msg.to) + xfer ||= ext.get_balance(msg.to) ext.set_balance(to, ext.get_balance(to)+xfer) ext.set_balance(msg.to, 0) ext.add_suicide(msg.to) diff --git a/test/contracts_test.rb b/test/contracts_test.rb index 03b3d08..24f2525 100644 --- a/test/contracts_test.rb +++ b/test/contracts_test.rb @@ -1104,7 +1104,7 @@ def test_ecrecover addr = Utils.keccak256(PublicKey.new(pub).encode(:bin)[1..-1])[12..-1] assert_equal PrivateKey.new(priv).to_address, addr - assert_equal Utils.big_endian_to_int(addr), c.test_ecrecover(Utils.big_endian_to_int(msghash), v, r, s) + assert_equal Utils.big_endian_to_int(addr), c.test_ecrecover(Utils.big_endian_to_int(msghash), Transaction.encode_v(v), r, s) end SHA256_CODE = <<-EOF diff --git a/test/lala_test.rb b/test/lala_test.rb deleted file mode 100644 index 8137de9..0000000 --- a/test/lala_test.rb +++ /dev/null @@ -1,25 +0,0 @@ -# -*- encoding : ascii-8bit -*- - -require 'test_helper' - -class LalaTest < Minitest::Test - include Ethereum - - def test_lala - priv = Utils.decode_hex 'd06ad30da01e9d83a26f41ea39c63323a365ad569a684e43c9983de0d64347d1' - p priv - p priv.size - p Utils.encode_hex(PrivateKey.new(priv).to_pubkey) - p Address.new(PrivateKey.new(priv).to_address).to_hex - msg = Utils.decode_hex 'c63ca8231343283681395197b0c35624173d378e83c70720e38a102c0c231812' - sig = Secp256k1.recoverable_sign msg, priv - puts "sig" - p sig - v, r, s = sig - p Utils.int_to_big_endian(r).bytes.map(&:ord) - p Utils.int_to_big_endian(s).bytes.map(&:ord) - pub = Secp256k1.recover_pubkey msg, sig - p Utils.encode_hex(pub) - end - -end diff --git a/test/special_contract_test.rb b/test/special_contract_test.rb index 31f8781..f6bb505 100644 --- a/test/special_contract_test.rb +++ b/test/special_contract_test.rb @@ -48,7 +48,7 @@ def test_ecrecover msg = Utils.zpad("ethereum", 32) v, r, s = Secp256k1.recoverable_sign(msg, priv.encode(:bin)) - sig = Utils.zpad_int(v) + Utils.zpad_int(r) + Utils.zpad_int(s) + sig = Utils.zpad_int(Transaction.encode_v(v)) + Utils.zpad_int(r) + Utils.zpad_int(s) cd = VM::CallData.new Utils.bytes_to_int_array(msg + sig) msg = Msg.new 0, cd diff --git a/test/state_test.rb b/test/state_test.rb index 2653d0c..03ac01a 100644 --- a/test/state_test.rb +++ b/test/state_test.rb @@ -8,17 +8,18 @@ class StateTest < Minitest::Test run_fixtures "StateTests", except: /stQuadraticComplexityTest|stMemoryStressTest|stPreCompiledContractsTransaction/ def on_fixture_test(name, data) - check_state_test data + config_overrides = get_config_overrides(name) + check_state_test data, config_overrides end - def check_state_test(params) - run_state_test params, :verify + def check_state_test(params, config_overrides={}) + run_state_test params, :verify, config_overrides end ENV_KEYS = %w(currentGasLimit currentTimestamp previousHash currentCoinbase currentDifficulty currentNumber).sort.freeze PRE_KEYS = %w(code nonce balance storage).sort.freeze - def run_state_test(params, mode) + def run_state_test(params, mode, config_overrides={}) pre = params['pre'] exek = params['transaction'] env = params['env'] @@ -27,7 +28,7 @@ def run_state_test(params, mode) assert_equal 40, env['currentCoinbase'].size # setup env - db_env = Env.new DB::EphemDB.new + db_env = Env.new DB::EphemDB.new, config: Env::DEFAULT_CONFIG.merge(config_overrides) header = BlockHeader.new( prevhash: decode_hex(env['previousHash']), number: parse_int_or_hex(env['currentNumber']), diff --git a/test/test_helper.rb b/test/test_helper.rb index 73e6541..ed4d561 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -374,6 +374,8 @@ def block_hash(n) class Minitest::Test class <