Class: Ethereum::ExternalCall
- Extended by:
- Forwardable
- Defined in:
- lib/ethereum/external_call.rb
Overview
External calls that can be made from inside the VM. To use the EVM with a different blockchain system, database, set parameters for testing, just swap out the functions here.
Instance Method Summary collapse
- #add_suicide(x) ⇒ Object
- #apply_msg(msg, code = nil) ⇒ Object
- #block_coinbase ⇒ Object
- #block_difficulty ⇒ Object
- #block_gas_limit ⇒ Object
- #block_hash(x) ⇒ Object
- #block_number ⇒ Object
- #block_timestamp ⇒ Object
- #create(msg) ⇒ Object
-
#initialize(block, tx) ⇒ ExternalCall
constructor
A new instance of ExternalCall.
- #log(addr, topics, data) ⇒ Object
- #log_storage(x) ⇒ Object
- #post_homestead_hardfork ⇒ Object
- #tx_gasprice ⇒ Object
- #tx_origin ⇒ Object
Constructor Details
#initialize(block, tx) ⇒ ExternalCall
Returns a new instance of ExternalCall.
17 18 19 20 |
# File 'lib/ethereum/external_call.rb', line 17 def initialize(block, tx) @block = block @tx = tx end |
Instance Method Details
#add_suicide(x) ⇒ Object
26 27 28 |
# File 'lib/ethereum/external_call.rb', line 26 def add_suicide(x) @block.suicides.push x end |
#apply_msg(msg, code = nil) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/ethereum/external_call.rb', line 124 def apply_msg(msg, code=nil) code ||= get_code msg.code_address log_msg.debug "MSG APPLY", sender: Utils.encode_hex(msg.sender), to: Utils.encode_hex(msg.to), gas: msg.gas, value: msg.value, data: Utils.encode_hex(msg.data.extract_all) log_state.trace "MSG PRE STATE SENDER", account: Utils.encode_hex(msg.sender), balance: get_balance(msg.sender), state: log_storage(msg.sender) log_state.trace "MSG PRE STATE RECIPIENT", account: Utils.encode_hex(msg.to), balance: get_balance(msg.to), state: log_storage(msg.to) # snapshot before execution snapshot = @block.snapshot # transfer value if msg.transfers_value unless @block.transfer_value(msg.sender, msg.to, msg.value) log_msg.debug "MSG TRANSFER FAILED", have: get_balance(msg.to), want: msg.value return [1, msg.gas, []] end end # main loop if SpecialContract[msg.code_address] res, gas, dat = SpecialContract[msg.code_address].call(self, msg) else res, gas, dat = VM.execute self, msg, code end log_msg.trace "MSG APPLIED", gas_remained: gas, sender: msg.sender, to: msg.to, data: dat log_state.trace "MSG POST STATE SENDER", account: Utils.encode_hex(msg.sender), balance: get_balance(msg.sender), state: log_storage(msg.sender) log_state.trace "MSG POST STATE RECIPIENT", account: Utils.encode_hex(msg.to), balance: get_balance(msg.to), state: log_storage(msg.to) if res == 0 log_msg.debug 'REVERTING' @block.revert snapshot end return res, gas, dat end |
#block_coinbase ⇒ Object
39 40 41 |
# File 'lib/ethereum/external_call.rb', line 39 def block_coinbase @block.coinbase end |
#block_difficulty ⇒ Object
51 52 53 |
# File 'lib/ethereum/external_call.rb', line 51 def block_difficulty @block.difficulty end |
#block_gas_limit ⇒ Object
55 56 57 |
# File 'lib/ethereum/external_call.rb', line 55 def block_gas_limit @block.gas_limit end |
#block_hash(x) ⇒ Object
30 31 32 33 34 35 36 37 |
# File 'lib/ethereum/external_call.rb', line 30 def block_hash(x) d = @block.number - x if d > 0 && d <= 256 @block.get_ancestor_hash d else Constant::BYTE_EMPTY end end |
#block_number ⇒ Object
47 48 49 |
# File 'lib/ethereum/external_call.rb', line 47 def block_number @block.number end |
#block_timestamp ⇒ Object
43 44 45 |
# File 'lib/ethereum/external_call.rb', line 43 def @block. end |
#create(msg) ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/ethereum/external_call.rb', line 75 def create(msg) log_msg.debug 'CONTRACT CREATION' sender = Utils.normalize_address(msg.sender, allow_blank: true) @block.increment_nonce msg.sender if tx_origin != msg.sender nonce = Utils.encode_int(@block.get_nonce(msg.sender) - 1) msg.to = Utils.mk_contract_address sender, nonce balance = get_balance(msg.to) if balance > 0 set_balance msg.to, balance @block.set_nonce msg.to, 0 @block.set_code msg.to, Constant::BYTE_EMPTY @block.reset_storage msg.to end msg.is_create = true code = msg.data.extract_all msg.data = VM::CallData.new [], 0, 0 snapshot = @block.snapshot res, gas, dat = apply_msg msg, code if res.true? return 1, gas, msg.to if dat.empty? gcost = 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 @block.number >= @block.config[:homestead_fork_blknum] @block.revert snapshot return 0, 0, Constant::BYTE_EMPTY end end @block.set_code msg.to, Utils.int_array_to_bytes(dat) return 1, gas, msg.to else return 0, gas, Constant::BYTE_EMPTY end end |
#log(addr, topics, data) ⇒ Object
59 60 61 |
# File 'lib/ethereum/external_call.rb', line 59 def log(addr, topics, data) @block.add_log Log.new(addr, topics, data) end |
#log_storage(x) ⇒ Object
22 23 24 |
# File 'lib/ethereum/external_call.rb', line 22 def log_storage(x) @block.account_to_dict(x)[:storage] end |
#post_homestead_hardfork ⇒ Object
71 72 73 |
# File 'lib/ethereum/external_call.rb', line 71 def post_homestead_hardfork @block.number >= @block.config[:homestead_fork_blknum] end |
#tx_gasprice ⇒ Object
67 68 69 |
# File 'lib/ethereum/external_call.rb', line 67 def tx_gasprice @tx.gasprice end |
#tx_origin ⇒ Object
63 64 65 |
# File 'lib/ethereum/external_call.rb', line 63 def tx_origin @tx.sender end |