def mk_independent_transaction_spv_proof(block, index): block = blocks.Block.init_from_header(block.db, block.list_header()) tx = transactions.Transaction.create(block.get_transaction(index)) block.get_receipt(index) if index > 0: pre_med, pre_gas, _, _ = block.get_receipt(index - 1) else: pre_med, pre_gas = block.get_parent().state_root, 0 block.state_root = pre_med block.gas_used = pre_gas nodes = mk_transaction_spv_proof(block, tx) nodes.extend( block.transactions.produce_spv_proof( rlp.encode(utils.encode_int(index)))) if index > 0: nodes.extend( block.transactions.produce_spv_proof( rlp.encode(utils.encode_int(index - 1)))) nodes = list(map(rlp.decode, list(set(map(rlp.encode, nodes))))) print(nodes) return rlp.encode([ utils.encode_int(64), block.get_parent().list_header(), block.list_header(), utils.encode_int(index), nodes ])
def sign_block(block, key, randao_parent, vchash, skips): block.header.extra_data = \ randao_parent + \ utils.zpad(utils.encode_int(skips), 32) + \ vchash for val in utils.ecsign(block.header.signing_hash, key): block.header.extra_data += utils.zpad(utils.encode_int(val), 32) return block
def to_dict(self): odict = self.storage_trie.to_dict() for k, v in self.storage_cache.items(): odict[utils.encode_int(k)] = rlp.encode(utils.encode_int(v)) return { 'balance': str(self.balance), 'nonce': str(self.nonce), 'code': '0x' + encode_hex(self.code), 'storage': { '0x' + encode_hex(key.lstrip(b'\x00') or b'\x00'): '0x' + encode_hex(rlp.decode(val)) for key, val in odict.items() } }
def commit_refcount_changes(self, epoch): # Save death row nodes timeout_epoch = epoch + self.ttl try: death_row_nodes = rlp.decode( self.db.get('deathrow:' + utils.to_string(timeout_epoch))) except BaseException: death_row_nodes = [] for nodekey in self.death_row: refcount, val = rlp.decode(self.db.get(b'r:' + nodekey)) if refcount == ZERO_ENCODED: new_refcount = utils.encode_int(DEATH_ROW_OFFSET + timeout_epoch) self.db.put(b'r:' + nodekey, rlp.encode([new_refcount, val])) if len(self.death_row) > 0: sys.stderr.write('%d nodes marked for pruning during block %d\n' % (len(self.death_row), timeout_epoch)) death_row_nodes.extend(self.death_row) self.death_row = [] self.db.put(b'deathrow:' + utils.to_string(timeout_epoch), rlp.encode(death_row_nodes)) # Save journal try: journal = rlp.decode( self.db.get(b'journal:' + utils.to_string(epoch))) except BaseException: journal = [] journal.extend(self.journal) self.journal = [] self.db.put(b'journal:' + utils.to_string(epoch), rlp.encode(journal))
def decode_event(self, log_topics, log_data): """ Return a dictionary representation the log. Note: This function won't work with anonymous events. Args: log_topics (List[bin]): The log's indexed arguments. log_data (bin): The encoded non-indexed arguments. """ # https://github.com/biblecoin/wiki/wiki/Biblecoin-Contract-ABI#function-selector-and-argument-encoding # topics[0]: keccak(EVENT_NAME+"("+EVENT_ARGS.map(canonical_type_of).join(",")+")") # If the event is declared as anonymous the topics[0] is not generated; if not len(log_topics) or log_topics[0] not in self.event_data: raise ValueError('Unknown log type') event_id_ = log_topics[0] event = self.event_data[event_id_] # data: abi_serialise(EVENT_NON_INDEXED_ARGS) # EVENT_NON_INDEXED_ARGS is the series of EVENT_ARGS that are not # indexed, abi_serialise is the ABI serialisation function used for # returning a series of typed values from a function. unindexed_types = [ type_ for type_, indexed in zip(event['types'], event['indexed']) if not indexed ] unindexed_args = decode_abi(unindexed_types, log_data) # topics[n]: EVENT_INDEXED_ARGS[n - 1] # EVENT_INDEXED_ARGS is the series of EVENT_ARGS that are indexed indexed_count = 1 # skip topics[0] result = {} for name, type_, indexed in zip( event['names'], event['types'], event['indexed']): if indexed: topic_bytes = utils.zpad( utils.encode_int(log_topics[indexed_count]), 32, ) indexed_count += 1 value = decode_single(process_type(type_), topic_bytes) else: value = unindexed_args.pop(0) result[name] = value result['_event_type'] = utils.to_string(event['name']) return result
def dec_refcount(self, k): # raise Exception("WHY AM I CHANGING A REFCOUNT?!:?") node_object = rlp.decode(self.db.get(b'r:' + k)) refcount = utils.decode_int(node_object[0]) if self.logging: sys.stderr.write('decreasing %s to: %d\n' % (utils.encode_hex(k), refcount - 1)) assert refcount > 0 self.journal.append([node_object[0], k]) new_refcount = utils.encode_int(refcount - 1) self.db.put(b'r:' + k, rlp.encode([new_refcount, node_object[1]])) if new_refcount == ZERO_ENCODED: self.death_row.append(k)
def inc_refcount(self, k, v): # raise Exception("WHY AM I CHANGING A REFCOUNT?!:?") try: node_object = rlp.decode(self.db.get(b'r:' + k)) refcount = utils.decode_int(node_object[0]) self.journal.append([node_object[0], k]) if refcount >= DEATH_ROW_OFFSET: refcount = 0 new_refcount = utils.encode_int(refcount + 1) self.db.put(b'r:' + k, rlp.encode([new_refcount, v])) if self.logging: sys.stderr.write('increasing %s %r to: %d\n' % (utils.encode_hex(k), v, refcount + 1)) except BaseException: self.db.put(b'r:' + k, rlp.encode([ONE_ENCODED, v])) self.journal.append([ZERO_ENCODED, k]) if self.logging: sys.stderr.write('increasing %s %r to: %d\n' % (utils.encode_hex(k), v, 1))
def encode_function_call(self, function_name, args): """ Return the encoded function call. Args: function_name (str): One of the existing functions described in the contract interface. args (List[object]): The function arguments that wll be encoded and used in the contract execution in the vm. Return: bin: The encoded function name and arguments so that it can be used with the evm to execute a funcion call, the binary string follows the Biblecoin Contract ABI. """ if function_name not in self.function_data: raise ValueError('Unkown function {}'.format(function_name)) description = self.function_data[function_name] function_selector = zpad(encode_int(description['prefix']), 4) arguments = encode_abi(description['encode_types'], args) return function_selector + arguments
def create_contract(ext, msg): log_msg.debug('CONTRACT CREATION') code = msg.data.extract_all() if ext.tx_origin != msg.sender: ext.increment_nonce(msg.sender) if ext.post_constantinople_hardfork() and msg.sender == null_address: msg.to = utils.mk_contract_address(msg.sender, 0) # msg.to = sha3(msg.sender + code)[12:] else: nonce = utils.encode_int(ext.get_nonce(msg.sender) - 1) msg.to = utils.mk_contract_address(msg.sender, nonce) if ext.post_metropolis_hardfork() and (ext.get_nonce(msg.to) or len(ext.get_code(msg.to))): log_msg.debug('CREATING CONTRACT ON TOP OF EXISTING CONTRACT') return 0, 0, b'' b = ext.get_balance(msg.to) if b > 0: ext.set_balance(msg.to, b) ext.set_nonce(msg.to, 0) ext.set_code(msg.to, b'') # ext.reset_storage(msg.to) msg.is_create = True # assert not ext.get_code(msg.to) msg.data = vm.CallData([], 0, 0) snapshot = ext.snapshot() ext.set_nonce(msg.to, 1 if ext.post_spurious_dragon_hardfork() else 0) res, gas, dat = _apply_msg(ext, msg, code) log_msg.debug('CONTRACT CREATION FINISHED', res=res, gas=gas, dat=dat if len(dat) < 2500 else ("data<%d>" % len(dat))) if res: if not len(dat): # ext.set_code(msg.to, b'') return 1, gas, msg.to gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost and (len(dat) <= 24576 or not ext.post_spurious_dragon_hardfork()): gas -= gcost else: dat = [] log_msg.debug('CONTRACT CREATION FAILED', have=gas, want=gcost, block_number=ext.block_number) if ext.post_homestead_hardfork(): ext.revert(snapshot) return 0, 0, b'' ext.set_code(msg.to, bytearray_to_bytestr(dat)) log_msg.debug('SETTING CODE', addr=encode_hex(msg.to), lendat=len(dat)) return 1, gas, msg.to else: ext.revert(snapshot) return 0, gas, dat
def vm_execute(ext, msg, code): # precompute trace flag # if we trace vm, we're in slow mode anyway trace_vm = log_vm_op.is_active('trace') compustate = Compustate(gas=msg.gas) stk = compustate.stack mem = compustate.memory if code in code_cache: processed_code = code_cache[code] else: processed_code = preprocess_code(code) code_cache[code] = processed_code # print(processed_code.keys(), code) codelen = len(code) s = time.time() steps = 0 _prevop = None # for trace only while compustate.pc in processed_code: ops, minstack, maxstack, totgas, nextpos = processed_code[ compustate.pc] if len(compustate.stack) < minstack: return vm_exception('INSUFFICIENT STACK') if len(compustate.stack) > maxstack: return vm_exception('STACK SIZE LIMIT EXCEEDED') if totgas > compustate.gas: return vm_exception('OUT OF GAS %d %d' % (totgas, compustate.gas)) jumped = False compustate.gas -= totgas compustate.pc = nextpos # Invalid operation; can only come at the end of a chunk if ops[-1][0] == 'INVALID': return vm_exception('INVALID OP', opcode=ops[-1][1]) for op, opcode, pushval in ops: if trace_vm: """ This diverges from normal logging, as we use the logging namespace only to decide which features get logged in 'bible.vm.op' i.e. tracing can not be activated by activating a sub like 'bible.vm.op.stack' """ trace_data = {} trace_data['stack'] = list( map(to_string, list(compustate.stack))) if _prevop in ('MLOAD', 'MSTORE', 'MSTORE8', 'SHA3', 'CALL', 'CALLCODE', 'CREATE', 'CALLDATACOPY', 'CODECOPY', 'EXTCODECOPY'): if len(compustate.memory) < 1024: trace_data['memory'] = \ ''.join([encode_hex(ascii_chr(x)) for x in compustate.memory]) else: trace_data['sha3memory'] = \ encode_hex(utils.sha3(b''.join([ascii_chr(x) for x in compustate.memory]))) if _prevop in ('SSTORE', ) or steps == 0: trace_data['storage'] = ext.log_storage(msg.to) trace_data['gas'] = to_string(compustate.gas + totgas) trace_data['inst'] = opcode trace_data['pc'] = to_string(compustate.pc - 1) if steps == 0: trace_data['depth'] = msg.depth trace_data['address'] = msg.to trace_data['steps'] = steps trace_data['depth'] = msg.depth if op[:4] == 'PUSH': trace_data['pushvalue'] = pushval log_vm_op.trace('vm', op=op, **trace_data) steps += 1 _prevop = op # Valid operations # Pushes first because they are very frequent if 0x60 <= opcode <= 0x7f: # compustate.pc += opcode - 0x5f # Move 1 byte forward for # 0x60, up to 32 bytes for 0x7f stk.append(pushval) elif opcode < 0x10: if op == 'STOP': return peaceful_exit('STOP', compustate.gas, []) elif op == 'ADD': stk.append((stk.pop() + stk.pop()) & TT256M1) elif op == 'SUB': stk.append((stk.pop() - stk.pop()) & TT256M1) elif op == 'MUL': stk.append((stk.pop() * stk.pop()) & TT256M1) elif op == 'DIV': s0, s1 = stk.pop(), stk.pop() stk.append(0 if s1 == 0 else s0 // s1) elif op == 'MOD': s0, s1 = stk.pop(), stk.pop() stk.append(0 if s1 == 0 else s0 % s1) elif op == 'SDIV': s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(0 if s1 == 0 else (abs(s0) // abs(s1) * (-1 if s0 * s1 < 0 else 1)) & TT256M1) elif op == 'SMOD': s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(0 if s1 == 0 else (abs(s0) % abs(s1) * (-1 if s0 < 0 else 1)) & TT256M1) elif op == 'ADDMOD': s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() stk.append((s0 + s1) % s2 if s2 else 0) elif op == 'MULMOD': s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() stk.append((s0 * s1) % s2 if s2 else 0) elif op == 'EXP': base, exponent = stk.pop(), stk.pop() # fee for exponent is dependent on its bytes # calc n bytes to represent exponent nbytes = len(utils.encode_int(exponent)) expfee = nbytes * opcodes.GEXPONENTBYTE if ext.post_clearing_hardfork(): expfee += opcodes.EXP_SUPPLEMENTAL_GAS * nbytes if compustate.gas < expfee: compustate.gas = 0 return vm_exception('OOG EXPONENT') compustate.gas -= expfee stk.append(pow(base, exponent, TT256)) elif op == 'SIGNEXTEND': s0, s1 = stk.pop(), stk.pop() if s0 <= 31: testbit = s0 * 8 + 7 if s1 & (1 << testbit): stk.append(s1 | (TT256 - (1 << testbit))) else: stk.append(s1 & ((1 << testbit) - 1)) else: stk.append(s1) elif opcode < 0x20: if op == 'LT': stk.append(1 if stk.pop() < stk.pop() else 0) elif op == 'GT': stk.append(1 if stk.pop() > stk.pop() else 0) elif op == 'SLT': s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(1 if s0 < s1 else 0) elif op == 'SGT': s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(1 if s0 > s1 else 0) elif op == 'EQ': stk.append(1 if stk.pop() == stk.pop() else 0) elif op == 'ISZERO': stk.append(0 if stk.pop() else 1) elif op == 'AND': stk.append(stk.pop() & stk.pop()) elif op == 'OR': stk.append(stk.pop() | stk.pop()) elif op == 'XOR': stk.append(stk.pop() ^ stk.pop()) elif op == 'NOT': stk.append(TT256M1 - stk.pop()) elif op == 'BYTE': s0, s1 = stk.pop(), stk.pop() if s0 >= 32: stk.append(0) else: stk.append((s1 // 256**(31 - s0)) % 256) elif opcode < 0x40: if op == 'SHA3': s0, s1 = stk.pop(), stk.pop() compustate.gas -= opcodes.GSHA3WORD * \ (utils.ceil32(s1) // 32) if compustate.gas < 0: return vm_exception('OOG PAYING FOR SHA3') if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') data = bytearray_to_bytestr(mem[s0:s0 + s1]) stk.append(utils.big_endian_to_int(utils.sha3(data))) elif op == 'ADDRESS': stk.append(utils.coerce_to_int(msg.to)) elif op == 'BALANCE': if ext.post_anti_dos_hardfork(): if not eat_gas(compustate, opcodes.BALANCE_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) stk.append(ext.get_balance(addr)) elif op == 'ORIGIN': stk.append(utils.coerce_to_int(ext.tx_origin)) elif op == 'CALLER': stk.append(utils.coerce_to_int(msg.sender)) elif op == 'CALLVALUE': stk.append(msg.value) elif op == 'CALLDATALOAD': stk.append(msg.data.extract32(stk.pop())) elif op == 'CALLDATASIZE': stk.append(msg.data.size) elif op == 'CALLDATACOPY': mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') msg.data.extract_copy(mem, mstart, dstart, size) elif op == 'CODESIZE': stk.append(len(code)) elif op == 'CODECOPY': mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') for i in range(size): if dstart + i < len(code): mem[mstart + i] = utils.safe_ord(code[dstart + i]) else: mem[mstart + i] = 0 elif op == 'RETURNDATACOPY': mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') if dstart + size > len(compustate.last_returned): return vm_exception('RETURNDATACOPY out of range') mem[mstart:mstart + size] = compustate.last_returned elif op == 'RETURNDATASIZE': stk.append(len(compustate.last_returned)) elif op == 'GASPRICE': stk.append(ext.tx_gasprice) elif op == 'EXTCODESIZE': if ext.post_anti_dos_hardfork(): if not eat_gas(compustate, opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) stk.append(len(ext.get_code(addr) or b'')) elif op == 'EXTCODECOPY': if ext.post_anti_dos_hardfork(): if not eat_gas(compustate, opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) start, s2, size = stk.pop(), stk.pop(), stk.pop() extcode = ext.get_code(addr) or b'' assert utils.is_string(extcode) if not mem_extend(mem, compustate, op, start, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') for i in range(size): if s2 + i < len(extcode): mem[start + i] = utils.safe_ord(extcode[s2 + i]) else: mem[start + i] = 0 elif opcode < 0x50: if op == 'BLOCKHASH': if ext.post_metropolis_hardfork() and False: bh_addr = ext.blockhash_store stk.append(ext.get_storage_data(bh_addr, stk.pop())) else: stk.append( utils.big_endian_to_int(ext.block_hash(stk.pop()))) elif op == 'COINBASE': stk.append(utils.big_endian_to_int(ext.block_coinbase)) elif op == 'TIMESTAMP': stk.append(ext.block_timestamp) elif op == 'NUMBER': stk.append(ext.block_number) elif op == 'DIFFICULTY': stk.append(ext.block_difficulty) elif op == 'GASLIMIT': stk.append(ext.block_gas_limit) elif opcode < 0x60: if op == 'POP': stk.pop() elif op == 'MLOAD': s0 = stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception('OOG EXTENDING MEMORY') stk.append(utils.bytes_to_int(mem[s0:s0 + 32])) elif op == 'MSTORE': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception('OOG EXTENDING MEMORY') mem[s0:s0 + 32] = utils.encode_int32(s1) elif op == 'MSTORE8': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 1): return vm_exception('OOG EXTENDING MEMORY') mem[s0] = s1 % 256 elif op == 'SLOAD': if ext.post_anti_dos_hardfork(): if not eat_gas(compustate, opcodes.SLOAD_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") stk.append(ext.get_storage_data(msg.to, stk.pop())) elif op == 'SSTORE': s0, s1 = stk.pop(), stk.pop() if msg.static: return vm_exception( 'Cannot SSTORE inside a static context') if ext.get_storage_data(msg.to, s0): gascost = opcodes.GSTORAGEMOD if s1 else opcodes.GSTORAGEKILL refund = 0 if s1 else opcodes.GSTORAGEREFUND else: gascost = opcodes.GSTORAGEADD if s1 else opcodes.GSTORAGEMOD refund = 0 if compustate.gas < gascost: return vm_exception('OUT OF GAS') compustate.gas -= gascost # adds neg gascost as a refund if below zero ext.add_refund(refund) ext.set_storage_data(msg.to, s0, s1) elif op == 'JUMP': compustate.pc = stk.pop() opnew = code[ compustate.pc] if compustate.pc < codelen else 0 jumped = True if opnew != JUMPDEST: return vm_exception('BAD JUMPDEST') elif op == 'JUMPI': s0, s1 = stk.pop(), stk.pop() if s1: compustate.pc = s0 opnew = code[ compustate.pc] if compustate.pc < codelen else 0 jumped = True if opnew != JUMPDEST: return vm_exception('BAD JUMPDEST') elif op == 'PC': stk.append(compustate.pc - 1) elif op == 'MSIZE': stk.append(len(mem)) elif op == 'GAS': stk.append(compustate.gas) # AFTER subtracting cost 1 elif op[:3] == 'DUP': # 0x7f - opcode is a negative number, -1 for 0x80 ... -16 for # 0x8f stk.append(stk[0x7f - opcode]) elif op[:4] == 'SWAP': # 0x8e - opcode is a negative number, -2 for 0x90 ... -17 for # 0x9f temp = stk[0x8e - opcode] stk[0x8e - opcode] = stk[-1] stk[-1] = temp elif op[:3] == 'LOG': """ 0xa0 ... 0xa4, 32/64/96/128/160 + len(data) gas a. Opcodes LOG0...LOG4 are added, takes 2-6 stack arguments MEMSTART MEMSZ (TOPIC1) (TOPIC2) (TOPIC3) (TOPIC4) b. Logs are kept track of during tx execution exactly the same way as suicides (except as an ordered list, not a set). Each log is in the form [address, [topic1, ... ], data] where: * address is what the ADDRESS opcode would output * data is mem[MEMSTART: MEMSTART + MEMSZ] * topics are as provided by the opcode c. The ordered list of logs in the transaction are expressed as [log0, log1, ..., logN]. """ depth = int(op[3:]) mstart, msz = stk.pop(), stk.pop() topics = [stk.pop() for x in range(depth)] compustate.gas -= msz * opcodes.GLOGBYTE if msg.static: return vm_exception('Cannot LOG inside a static context') if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') data = bytearray_to_bytestr(mem[mstart:mstart + msz]) ext.log(msg.to, topics, data) log_log.trace('LOG', to=msg.to, topics=topics, data=list(map(utils.safe_ord, data))) # print('LOG', msg.to, topics, list(map(ord, data))) elif op == 'CREATE': value, mstart, msz = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') if msg.static: return vm_exception( 'Cannot CREATE inside a static context') if ext.get_balance(msg.to) >= value and msg.depth < MAX_DEPTH: cd = CallData(mem, mstart, msz) ingas = compustate.gas if ext.post_anti_dos_hardfork(): ingas = all_but_1n(ingas, opcodes.CALL_CHILD_LIMIT_DENOM) create_msg = Message(msg.to, b'', value, ingas, cd, msg.depth + 1) o, gas, addr = ext.create(create_msg) if o: stk.append(utils.coerce_to_int(addr)) else: stk.append(0) compustate.gas = compustate.gas - ingas + gas else: stk.append(0) elif op in ('CALL', 'CALLCODE', 'DELEGATECALL', 'STATICCALL'): # Pull arguments from the stack if op in ('CALL', 'CALLCODE'): gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() else: gas, to, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() value = 0 # Static context prohibition if msg.static and value > 0: return vm_exception( 'Cannot make a non-zero-value call inside a static context' ) # Expand memory if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ not mem_extend(mem, compustate, op, memoutstart, memoutsz): return vm_exception('OOG EXTENDING MEMORY') to = utils.int_to_addr(to) # Extra gas costs based on hard fork-dependent factors extra_gas = (not ext.account_exists(to)) * (op == 'CALL') * (value > 0 or not ext.post_clearing_hardfork()) * opcodes.GCALLNEWACCOUNT + \ (value > 0) * opcodes.GCALLVALUETRANSFER + \ ext.post_anti_dos_hardfork() * opcodes.CALL_SUPPLEMENTAL_GAS # Compute child gas limit if ext.post_anti_dos_hardfork(): if compustate.gas < extra_gas: return vm_exception('OUT OF GAS', needed=extra_gas) gas = min( gas, all_but_1n(compustate.gas - extra_gas, opcodes.CALL_CHILD_LIMIT_DENOM)) else: if compustate.gas < gas + extra_gas: return vm_exception('OUT OF GAS', needed=gas + extra_gas) submsg_gas = gas + opcodes.GSTIPEND * (value > 0) # Verify that there is sufficient balance and depth if ext.get_balance(msg.to) < value or msg.depth >= MAX_DEPTH: compustate.gas -= (gas + extra_gas - submsg_gas) stk.append(0) else: # Subtract gas from parent compustate.gas -= (gas + extra_gas) assert compustate.gas >= 0 cd = CallData(mem, meminstart, meminsz) # Generate the message if op == 'CALL': call_msg = Message(msg.to, to, value, submsg_gas, cd, msg.depth + 1, code_address=to, static=msg.static) elif ext.post_homestead_hardfork( ) and op == 'DELEGATECALL': call_msg = Message(msg.sender, msg.to, msg.value, submsg_gas, cd, msg.depth + 1, code_address=to, transfers_value=False, static=msg.static) elif op == 'DELEGATECALL': return vm_exception('OPCODE INACTIVE') elif op == 'CALLCODE': call_msg = Message(msg.to, msg.to, value, submsg_gas, cd, msg.depth + 1, code_address=to, static=msg.static) elif op == 'STATICCALL': call_msg = Message(msg.to, to, value, submsg_gas, cd, msg.depth + 1, code_address=to, static=True) else: raise Exception("Lolwut") # Get result result, gas, data = ext.msg(call_msg) if result == 0: stk.append(0) else: stk.append(1) # Set output memory for i in range(min(len(data), memoutsz)): mem[memoutstart + i] = data[i] compustate.gas += gas compustate.last_returned = bytearray(data) elif op == 'RETURN': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') return peaceful_exit('RETURN', compustate.gas, mem[s0:s0 + s1]) elif op == 'REVERT': if not ext.post_metropolis_hardfork(): return vm_exception('Opcode not yet enabled') s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') return revert(compustate.gas, mem[s0:s0 + s1]) elif op == 'SUICIDE': if msg.static: return vm_exception( 'Cannot SUICIDE inside a static context') to = utils.encode_int(stk.pop()) to = ((b'\x00' * (32 - len(to))) + to)[12:] xfer = ext.get_balance(msg.to) if ext.post_anti_dos_hardfork(): extra_gas = opcodes.SUICIDE_SUPPLEMENTAL_GAS + \ (not ext.account_exists( to)) * (xfer > 0 or not ext.post_clearing_hardfork()) * opcodes.GCALLNEWACCOUNT if not eat_gas(compustate, extra_gas): return vm_exception("OUT OF GAS") ext.set_balance(to, ext.get_balance(to) + xfer) ext.set_balance(msg.to, 0) ext.add_suicide(msg.to) log_msg.debug('SUICIDING', addr=utils.checksum_encode(msg.to), to=utils.checksum_encode(to), xferring=xfer) return 1, compustate.gas, [] # assert utils.is_numeric(compustate.gas) # this is slow! # for a in stk: # assert is_numeric(a), (op, stk) # assert a >= 0 and a < 2**256, (a, op, stk) # if not jumped: # assert compustate.pc == nextpos # compustate.pc = nextpos if compustate.pc >= codelen: return peaceful_exit('CODE OUT OF RANGE', compustate.gas, []) return vm_exception('INVALID JUMP')
raise Exception("nibbles can only be [0,..15]") if len(nibbles) % 2: raise Exception("nibbles must be of even numbers") res = b'' for i in range(0, len(nibbles), 2): res += ascii_chr(16 * nibbles[i] + nibbles[i + 1]) return res NIBBLE_TERMINATOR = 16 RECORDING = 1 NONE = 0 VERIFYING = -1 ZERO_ENCODED = utils.encode_int(0) proving = False class ProofConstructor(): def __init__(self): self.mode = [] self.nodes = [] self.exempt = [] def push(self, mode, nodes=[]): global proving proving = True self.mode.append(mode) self.exempt.append(set())
from rlp.utils import decode_hex from biblecoin import utils from biblecoin.db import BaseDB, EphemDB from biblecoin.child_dao_list import L as child_dao_list import copy default_config = dict( # Genesis block difficulty GENESIS_DIFFICULTY=131072, # Genesis block gas limit GENESIS_GAS_LIMIT=3141592, # Genesis block prevhash, coinbase, nonce GENESIS_PREVHASH=b'\x00' * 32, GENESIS_COINBASE=b'\x00' * 20, GENESIS_NONCE=utils.zpad(utils.encode_int(42), 8), GENESIS_MIXHASH=b'\x00' * 32, GENESIS_TIMESTAMP=0, GENESIS_EXTRA_DATA=b'', GENESIS_INITIAL_ALLOC={}, # Minimum gas limit MIN_GAS_LIMIT=5000, MAX_GAS_LIMIT=2**63 - 1, # Gas limit adjustment algo: # block.gas_limit=block.parent.gas_limit * 1023/1024 + # (block.gas_used * 6 / 5) / 1024 GASLIMIT_EMA_FACTOR=1024, GASLIMIT_ADJMAX_FACTOR=1024, BLOCK_GAS_LIMIT=4712388, BLKLIM_FACTOR_NOM=3, BLKLIM_FACTOR_DEN=2,
def encode_single(typ, arg): # pylint: disable=too-many-return-statements,too-many-branches,too-many-statements,too-many-locals """ Encode `arg` as `typ`. `arg` will be encoded in a best effort manner, were necessary the function will try to correctly define the underlying binary representation (ie. decoding a hex-encoded address/hash). Args: typ (Tuple[(str, int, list)]): A 3-tuple defining the `arg` type. The first element defines the type name. The second element defines the type length in bits. The third element defines if it's an array type. Together the first and second defines the elementary type, the third element must be present but is ignored. Valid type names are: - uint - int - bool - ufixed - fixed - string - bytes - hash - address arg (object): The object to be encoded, it must be a python object compatible with the `typ`. Raises: ValueError: when an invalid `typ` is supplied. ValueOutOfBounds: when `arg` cannot be encoded as `typ` because of the binary contraints. Note: This function don't work with array types, for that use the `enc` function. """ base, sub, _ = typ if base == 'uint': sub = int(sub) if not (0 < sub <= 256 and sub % 8 == 0): raise ValueError( 'invalid unsigned integer bit length {}'.format(sub)) try: i = decint(arg, signed=False) except EncodingError: # arg is larger than 2**256 raise ValueOutOfBounds(repr(arg)) if not 0 <= i < 2 ** sub: raise ValueOutOfBounds(repr(arg)) value_encoded = int_to_big_endian(i) return zpad(value_encoded, 32) if base == 'int': sub = int(sub) bits = sub - 1 if not (0 < sub <= 256 and sub % 8 == 0): raise ValueError('invalid integer bit length {}'.format(sub)) try: i = decint(arg, signed=True) except EncodingError: # arg is larger than 2**255 raise ValueOutOfBounds(repr(arg)) if not -2 ** bits <= i < 2 ** bits: raise ValueOutOfBounds(repr(arg)) value = i % 2 ** 256 # convert negative to "equivalent" positive value_encoded = int_to_big_endian(value) return zpad(value_encoded, 32) if base == 'bool': if arg is True: value_encoded = int_to_big_endian(1) elif arg is False: value_encoded = int_to_big_endian(0) else: raise ValueError('%r is not bool' % arg) return zpad(value_encoded, 32) if base == 'ufixed': sub = str(sub) # pylint: disable=redefined-variable-type high_str, low_str = sub.split('x') high = int(high_str) low = int(low_str) if not (0 < high + low <= 256 and high % 8 == 0 and low % 8 == 0): raise ValueError('invalid unsigned fixed length {}'.format(sub)) if not 0 <= arg < 2 ** high: raise ValueOutOfBounds(repr(arg)) float_point = arg * 2 ** low fixed_point = int(float_point) return zpad(int_to_big_endian(fixed_point), 32) if base == 'fixed': sub = str(sub) # pylint: disable=redefined-variable-type high_str, low_str = sub.split('x') high = int(high_str) low = int(low_str) bits = high - 1 if not (0 < high + low <= 256 and high % 8 == 0 and low % 8 == 0): raise ValueError('invalid unsigned fixed length {}'.format(sub)) if not -2 ** bits <= arg < 2 ** bits: raise ValueOutOfBounds(repr(arg)) float_point = arg * 2 ** low fixed_point = int(float_point) value = fixed_point % 2 ** 256 return zpad(int_to_big_endian(value), 32) # Decimals if base == 'decimal': val_to_encode = int(arg * 10**int(sub)) return zpad(encode_int(val_to_encode % 2**256), 32) if base == 'string': if isinstance(arg, utils.unicode): arg = arg.encode('utf8') else: try: arg.decode('utf8') except UnicodeDecodeError: raise ValueError('string must be utf8 encoded') if len(sub): # fixed length if not 0 <= len(arg) <= int(sub): raise ValueError('invalid string length {}'.format(sub)) if not 0 <= int(sub) <= 32: raise ValueError('invalid string length {}'.format(sub)) return rzpad(arg, 32) if not 0 <= len(arg) < TT256: raise Exception('Integer invalid or out of range: %r' % arg) length_encoded = zpad(int_to_big_endian(len(arg)), 32) value_encoded = rzpad(arg, utils.ceil32(len(arg))) return length_encoded + value_encoded if base == 'bytes': if not is_string(arg): if isinstance(arg, str): arg = bytes(arg, 'utf8') else: raise EncodingError('Expecting string: %r' % arg) arg = utils.to_string(arg) # py2: force unicode into str if len(sub): # fixed length if not 0 <= len(arg) <= int(sub): raise ValueError('string must be utf8 encoded') if not 0 <= int(sub) <= 32: raise ValueError('string must be utf8 encoded') return rzpad(arg, 32) if not 0 <= len(arg) < TT256: raise Exception('Integer invalid or out of range: %r' % arg) length_encoded = zpad(int_to_big_endian(len(arg)), 32) value_encoded = rzpad(arg, utils.ceil32(len(arg))) return length_encoded + value_encoded if base == 'hash': if not (int(sub) and int(sub) <= 32): raise EncodingError('too long: %r' % arg) if is_numeric(arg): return zpad(encode_int(arg), 32) if len(arg) == int(sub): return zpad(arg, 32) if len(arg) == int(sub) * 2: return zpad(decode_hex(arg), 32) raise EncodingError('Could not parse hash: %r' % arg) if base == 'address': assert sub == '' if is_numeric(arg): return zpad(encode_int(arg), 32) if len(arg) == 20: return zpad(arg, 32) if len(arg) == 40: return zpad(decode_hex(arg), 32) if len(arg) == 42 and arg[:2] == '0x': return zpad(decode_hex(arg[2:]), 32) raise EncodingError('Could not parse address: %r' % arg) raise EncodingError('Unhandled type: %r %r' % (base, sub))
def sub1(b): v = utils.big_endian_to_int(b) return utils.zpad(utils.encode_int(v - 1), 4)
def add1(b): v = utils.big_endian_to_int(b) return utils.zpad(utils.encode_int(v + 1), 4)
def vm_execute(ext, msg, code): # precompute trace flag # if we trace vm, we're in slow mode anyway trace_vm = log_vm_op.is_active('trace') compustate = Compustate(gas=msg.gas) stk = compustate.stack mem = compustate.memory processed_code = preprocess_code(code) s = time.time() op = None steps = 0 _prevop = None # for trace only while True: # print('op: ', op, time.time() - s) # s = time.time() # stack size limit error if compustate.pc not in processed_code: return vm_exception('INVALID START POINT') _data = processed_code[compustate.pc] gas, min_stack, max_stack, compustate.pc = _data[:4] ops = _data[4:] # out of gas error if gas > compustate.gas: return vm_exception('OUT OF GAS') # insufficient stack error if not (min_stack <= len(compustate.stack) <= max_stack): return vm_exception('INCOMPATIBLE STACK LENGTH', min_stack=min_stack, have=len(compustate.stack), max_stack=max_stack) # Apply operation compustate.gas -= gas for op in ops: if trace_vm: """ This diverges from normal logging, as we use the logging namespace only to decide which features get logged in 'bible.vm.op' i.e. tracing can not be activated by activating a sub like 'bible.vm.op.stack' """ trace_data = {} trace_data['stack'] = list( map(to_string, list(compustate.stack))) if _prevop in (op_MLOAD, op_MSTORE, op_MSTORE8, op_SHA3, op_CALL, op_CALLCODE, op_CREATE, op_CALLDATACOPY, op_CODECOPY, op_EXTCODECOPY): if len(compustate.memory) < 1024: trace_data['memory'] = \ b''.join([encode_hex(ascii_chr(x)) for x in compustate.memory]) else: trace_data['sha3memory'] = \ encode_hex(utils.sha3(''.join([ascii_chr(x) for x in compustate.memory]))) if _prevop in (op_SSTORE, op_SLOAD) or steps == 0: trace_data['storage'] = ext.log_storage(msg.to) # trace_data['gas'] = to_string(compustate.gas + fee) trace_data['inst'] = op trace_data['pc'] = to_string(compustate.pc - 1) if steps == 0: trace_data['depth'] = msg.depth trace_data['address'] = msg.to trace_data['op'] = op trace_data['steps'] = steps # if op[:4] == 'PUSH': # trace_data['pushvalue'] = pushval log_vm_op.trace('vm', **trace_data) steps += 1 _prevop = op # Invalid operation if op == INVALID: return vm_exception('INVALID OP', opcode=op) # Valid operations if op < 0x10: if op == op_STOP: return peaceful_exit('STOP', compustate.gas, []) elif op == op_ADD: stk.append((stk.pop() + stk.pop()) & TT256M1) elif op == op_SUB: stk.append((stk.pop() - stk.pop()) & TT256M1) elif op == op_MUL: stk.append((stk.pop() * stk.pop()) & TT256M1) elif op == op_DIV: s0, s1 = stk.pop(), stk.pop() stk.append(0 if s1 == 0 else s0 // s1) elif op == op_MOD: s0, s1 = stk.pop(), stk.pop() stk.append(0 if s1 == 0 else s0 % s1) elif op == op_SDIV: s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(0 if s1 == 0 else (abs(s0) // abs(s1) * (-1 if s0 * s1 < 0 else 1)) & TT256M1) elif op == op_SMOD: s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(0 if s1 == 0 else (abs(s0) % abs(s1) * (-1 if s0 < 0 else 1)) & TT256M1) elif op == op_ADDMOD: s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() stk.append((s0 + s1) % s2 if s2 else 0) elif op == op_MULMOD: s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() stk.append((s0 * s1) % s2 if s2 else 0) elif op == op_EXP: base, exponent = stk.pop(), stk.pop() # fee for exponent is dependent on its bytes # calc n bytes to represent exponent nbytes = len(utils.encode_int(exponent)) expfee = nbytes * opcodes.GEXPONENTBYTE if compustate.gas < expfee: compustate.gas = 0 return vm_exception('OOG EXPONENT') compustate.gas -= expfee stk.append(pow(base, exponent, TT256)) elif op == op_SIGNEXTEND: s0, s1 = stk.pop(), stk.pop() if s0 <= 31: testbit = s0 * 8 + 7 if s1 & (1 << testbit): stk.append(s1 | (TT256 - (1 << testbit))) else: stk.append(s1 & ((1 << testbit) - 1)) else: stk.append(s1) elif op < 0x20: if op == op_LT: stk.append(1 if stk.pop() < stk.pop() else 0) elif op == op_GT: stk.append(1 if stk.pop() > stk.pop() else 0) elif op == op_SLT: s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(1 if s0 < s1 else 0) elif op == op_SGT: s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(1 if s0 > s1 else 0) elif op == op_EQ: stk.append(1 if stk.pop() == stk.pop() else 0) elif op == op_ISZERO: stk.append(0 if stk.pop() else 1) elif op == op_AND: stk.append(stk.pop() & stk.pop()) elif op == op_OR: stk.append(stk.pop() | stk.pop()) elif op == op_XOR: stk.append(stk.pop() ^ stk.pop()) elif op == op_NOT: stk.append(TT256M1 - stk.pop()) elif op == op_BYTE: s0, s1 = stk.pop(), stk.pop() if s0 >= 32: stk.append(0) else: stk.append((s1 // 256**(31 - s0)) % 256) elif op < 0x40: if op == op_SHA3: s0, s1 = stk.pop(), stk.pop() compustate.gas -= opcodes.GSHA3WORD * \ (utils.ceil32(s1) // 32) if compustate.gas < 0: return vm_exception('OOG PAYING FOR SHA3') if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') data = b''.join(map(ascii_chr, mem[s0:s0 + s1])) stk.append(utils.big_endian_to_int(utils.sha3(data))) elif op == op_ADDRESS: stk.append(utils.coerce_to_int(msg.to)) elif op == op_BALANCE: addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) stk.append(ext.get_balance(addr)) elif op == op_ORIGIN: stk.append(utils.coerce_to_int(ext.tx_origin)) elif op == op_CALLER: stk.append(utils.coerce_to_int(msg.sender)) elif op == op_CALLVALUE: stk.append(msg.value) elif op == op_CALLDATALOAD: stk.append(msg.data.extract32(stk.pop())) elif op == op_CALLDATASIZE: stk.append(msg.data.size) elif op == op_CALLDATACOPY: mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') msg.data.extract_copy(mem, mstart, dstart, size) elif op == op_CODESIZE: stk.append(len(code)) elif op == op_CODECOPY: start, s1, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, start, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') for i in range(size): if s1 + i < len(code): mem[start + i] = utils.safe_ord(code[s1 + i]) else: mem[start + i] = 0 elif op == op_GASPRICE: stk.append(ext.tx_gasprice) elif op == op_EXTCODESIZE: addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) stk.append(len(ext.get_code(addr) or b'')) elif op == op_EXTCODECOPY: addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) start, s2, size = stk.pop(), stk.pop(), stk.pop() extcode = ext.get_code(addr) or b'' assert utils.is_string(extcode) if not mem_extend(mem, compustate, op, start, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') for i in range(size): if s2 + i < len(extcode): mem[start + i] = utils.safe_ord(extcode[s2 + i]) else: mem[start + i] = 0 elif op < 0x50: if op == op_BLOCKHASH: stk.append( utils.big_endian_to_int(ext.block_hash(stk.pop()))) elif op == op_COINBASE: stk.append(utils.big_endian_to_int(ext.block_coinbase)) elif op == op_TIMESTAMP: stk.append(ext.block_timestamp) elif op == op_NUMBER: stk.append(ext.block_number) elif op == op_DIFFICULTY: stk.append(ext.block_difficulty) elif op == op_GASLIMIT: stk.append(ext.block_gas_limit) elif op < 0x60: if op == op_POP: stk.pop() elif op == op_MLOAD: s0 = stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception('OOG EXTENDING MEMORY') data = 0 for c in mem[s0:s0 + 32]: data = (data << 8) + c stk.append(data) elif op == op_MSTORE: s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception('OOG EXTENDING MEMORY') v = s1 for i in range(31, -1, -1): mem[s0 + i] = v % 256 v //= 256 elif op == op_MSTORE8: s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 1): return vm_exception('OOG EXTENDING MEMORY') mem[s0] = s1 % 256 elif op == op_SLOAD: stk.append(ext.get_storage_data(msg.to, stk.pop())) elif op == op_SSTORE: s0, s1 = stk.pop(), stk.pop() if ext.get_storage_data(msg.to, s0): gascost = opcodes.GSTORAGEMOD if s1 else opcodes.GSTORAGEKILL refund = 0 if s1 else opcodes.GSTORAGEREFUND else: gascost = opcodes.GSTORAGEADD if s1 else opcodes.GSTORAGEMOD refund = 0 if compustate.gas < gascost: return vm_exception('OUT OF GAS') compustate.gas -= gascost # adds neg gascost as a refund if below zero ext.add_refund(refund) ext.set_storage_data(msg.to, s0, s1) elif op == op_JUMP: compustate.pc = stk.pop() opnew = processed_code[compustate.pc][4] if \ compustate.pc in processed_code else op_STOP if opnew != op_JUMPDEST: return vm_exception('BAD JUMPDEST') elif op == op_JUMPI: s0, s1 = stk.pop(), stk.pop() if s1: compustate.pc = s0 opnew = processed_code[compustate.pc][4] if \ compustate.pc in processed_code else op_STOP if opnew != op_JUMPDEST: return vm_exception('BAD JUMPDEST') elif op == op_PC: stk.append(compustate.pc - 1) elif op == op_MSIZE: stk.append(len(mem)) elif op == op_GAS: stk.append(compustate.gas) # AFTER subtracting cost 1 elif op_PUSH1 <= (op & 255) <= op_PUSH32: # Hide push value in high-order bytes of op stk.append(op >> 8) elif op_DUP1 <= op <= op_DUP16: depth = op - op_DUP1 + 1 stk.append(stk[-depth]) elif op_SWAP1 <= op <= op_SWAP16: depth = op - op_SWAP1 + 1 temp = stk[-depth - 1] stk[-depth - 1] = stk[-1] stk[-1] = temp elif op_LOG0 <= op <= op_LOG4: """ 0xa0 ... 0xa4, 32/64/96/128/160 + len(data) gas a. Opcodes LOG0...LOG4 are added, takes 2-6 stack arguments MEMSTART MEMSZ (TOPIC1) (TOPIC2) (TOPIC3) (TOPIC4) b. Logs are kept track of during tx execution exactly the same way as suicides (except as an ordered list, not a set). Each log is in the form [address, [topic1, ... ], data] where: * address is what the ADDRESS opcode would output * data is mem[MEMSTART: MEMSTART + MEMSZ] * topics are as provided by the opcode c. The ordered list of logs in the transaction are expressed as [log0, log1, ..., logN]. """ depth = op - op_LOG0 mstart, msz = stk.pop(), stk.pop() topics = [stk.pop() for x in range(depth)] compustate.gas -= msz * opcodes.GLOGBYTE if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') data = b''.join(map(ascii_chr, mem[mstart:mstart + msz])) ext.log(msg.to, topics, data) log_log.trace('LOG', to=msg.to, topics=topics, data=list(map(utils.safe_ord, data))) # print('LOG', msg.to, topics, list(map(ord, data))) elif op == op_CREATE: value, mstart, msz = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') if ext.get_balance(msg.to) >= value and msg.depth < 1024: cd = CallData(mem, mstart, msz) create_msg = Message(msg.to, b'', value, compustate.gas, cd, msg.depth + 1) o, gas, addr = ext.create(create_msg) if o: stk.append(utils.coerce_to_int(addr)) compustate.gas = gas else: stk.append(0) compustate.gas = 0 else: stk.append(0) elif op == op_CALL: gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ not mem_extend(mem, compustate, op, memoutstart, memoutsz): return vm_exception('OOG EXTENDING MEMORY') to = utils.encode_int(to) to = ((b'\x00' * (32 - len(to))) + to)[12:] extra_gas = (not ext.account_exists(to)) * opcodes.GCALLNEWACCOUNT + \ (value > 0) * opcodes.GCALLVALUETRANSFER submsg_gas = gas + opcodes.GSTIPEND * (value > 0) if compustate.gas < gas + extra_gas: return vm_exception('OUT OF GAS', needed=gas + extra_gas) if ext.get_balance(msg.to) >= value and msg.depth < 1024: compustate.gas -= (gas + extra_gas) cd = CallData(mem, meminstart, meminsz) call_msg = Message(msg.to, to, value, submsg_gas, cd, msg.depth + 1, code_address=to) result, gas, data = ext.msg(call_msg) if result == 0: stk.append(0) else: stk.append(1) compustate.gas += gas for i in range(min(len(data), memoutsz)): mem[memoutstart + i] = data[i] else: compustate.gas -= (gas + extra_gas - submsg_gas) stk.append(0) elif op == op_CALLCODE: gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ not mem_extend(mem, compustate, op, memoutstart, memoutsz): return vm_exception('OOG EXTENDING MEMORY') extra_gas = (value > 0) * opcodes.GCALLVALUETRANSFER submsg_gas = gas + opcodes.GSTIPEND * (value > 0) if compustate.gas < gas + extra_gas: return vm_exception('OUT OF GAS', needed=gas + extra_gas) if ext.get_balance(msg.to) >= value and msg.depth < 1024: compustate.gas -= (gas + extra_gas) to = utils.encode_int(to) to = ((b'\x00' * (32 - len(to))) + to)[12:] cd = CallData(mem, meminstart, meminsz) call_msg = Message(msg.to, msg.to, value, submsg_gas, cd, msg.depth + 1, code_address=to) result, gas, data = ext.msg(call_msg) if result == 0: stk.append(0) else: stk.append(1) compustate.gas += gas for i in range(min(len(data), memoutsz)): mem[memoutstart + i] = data[i] else: compustate.gas -= (gas + extra_gas - submsg_gas) stk.append(0) elif op == op_RETURN: s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') return peaceful_exit('RETURN', compustate.gas, mem[s0:s0 + s1]) elif op == op_SUICIDE: to = utils.encode_int(stk.pop()) to = ((b'\x00' * (32 - len(to))) + to)[12:] 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) # print('suiciding %s %s %d' % (msg.to, to, xfer)) return 1, compustate.gas, []