コード例 #1
0
ファイル: vm.py プロジェクト: zendcreative/pyquarkchain
def vm_trace(ext, msg, compustate, opcode, pushcache, tracer=log_vm_op):
    """
    This diverges from normal logging, as we use the logging namespace
    only to decide which features get logged in 'eth.vm.op'
    i.e. tracing can not be activated by activating a sub
    like 'eth.vm.op.stack'
    """

    op, in_args, out_args, fee = opcodes.opcodes[opcode]

    trace_data = {}
    trace_data["stack"] = list(map(to_string, list(compustate.prev_stack)))
    if compustate.prev_prev_op in (
        "MLOAD",
        "MSTORE",
        "MSTORE8",
        "SHA3",
        "CALL",
        "CALLCODE",
        "CREATE",
        "CALLDATACOPY",
        "CODECOPY",
        "EXTCODECOPY",
    ):
        if len(compustate.prev_memory) < 4096:
            trace_data["memory"] = "".join(
                [encode_hex(ascii_chr(x)) for x in compustate.prev_memory]
            )
        else:
            trace_data["sha3memory"] = encode_hex(
                utils.sha3(b"".join([ascii_chr(x) for x in compustate.prev_memory]))
            )
    if compustate.prev_prev_op in ("SSTORE",) or compustate.steps == 0:
        trace_data["storage"] = ext.log_storage(msg.to)
    trace_data["gas"] = to_string(compustate.prev_gas)
    trace_data["gas_cost"] = to_string(compustate.prev_gas - compustate.gas)
    trace_data["fee"] = fee
    trace_data["inst"] = opcode
    trace_data["pc"] = to_string(compustate.prev_pc)
    if compustate.steps == 0:
        trace_data["depth"] = msg.depth
        trace_data["address"] = msg.to
    trace_data["steps"] = compustate.steps
    trace_data["depth"] = msg.depth
    if op[:4] == "PUSH":
        print(repr(pushcache))
        trace_data["pushvalue"] = pushcache[compustate.prev_pc]
    tracer.trace("vm", op=op, **trace_data)
    compustate.steps += 1
    compustate.prev_prev_op = op
コード例 #2
0
ファイル: transactions.py プロジェクト: wub11/pyetherum
 def intrinsic_gas_used(self):
     num_zero_bytes = str_to_bytes(self.data).count(ascii_chr(0))
     num_non_zero_bytes = len(self.data) - num_zero_bytes
     return (opcodes.GTXCOST
             #         + (0 if self.to else opcodes.CREATE[3])
             + opcodes.GTXDATAZERO * num_zero_bytes
             + opcodes.GTXDATANONZERO * num_non_zero_bytes)
コード例 #3
0
ファイル: tester.py プロジェクト: 4gn3s/pyethereum
 def _send(self, sender, to, value, evmdata='', output=None,
           funid=None, abi=None, profiling=0):
     if funid is not None or abi is not None:
         raise Exception("Send with funid+abi is deprecated. Please use"
                         " the abi_contract mechanism")
     tm, g = time.time(), self.block.gas_used
     sendnonce = self.block.get_nonce(u.privtoaddr(sender))
     tx = t.Transaction(sendnonce, gas_price, gas_limit, to, value, evmdata)
     self.last_tx = tx
     tx.sign(sender)
     recorder = LogRecorder() if profiling > 1 else None
     (s, o) = pb.apply_transaction(self.block, tx)
     if not s:
         raise TransactionFailed()
     out = {"output": o}
     if profiling > 0:
         zero_bytes = tx.data.count(ascii_chr(0))
         non_zero_bytes = len(tx.data) - zero_bytes
         intrinsic_gas_used = opcodes.GTXDATAZERO * zero_bytes + \
             opcodes.GTXDATANONZERO * non_zero_bytes
         ntm, ng = time.time(), self.block.gas_used
         out["time"] = ntm - tm
         out["gas"] = ng - g - intrinsic_gas_used
     if profiling > 1:
         trace = recorder.pop_records()
         ops = [x['op'] for x in trace if x['event'] == 'vm']
         opdict = {}
         for op in ops:
             opdict[op] = opdict.get(op, 0) + 1
         out["ops"] = opdict
     return out
コード例 #4
0
def vm_trace(ext, msg, compustate, opcode, pushcache):#, tracer=log_vm_op):
    """
    This diverges from normal logging, as we use the logging namespace
    only to decide which features get logged in 'eth.vm.op'
    i.e. tracing can not be activated by activating a sub
    like 'eth.vm.op.stack'
    """

    op, in_args, out_args, fee = opcodes.opcodes[opcode]

    trace_data = {}
    trace_data['stack'] = list(map(utils.to_string, list(compustate.prev_stack)))
    if compustate.prev_prev_op in ('MLOAD', 'MSTORE', 'MSTORE8', 'SHA3', 'CALL',
                   'CALLCODE', 'CREATE', 'CALLDATACOPY', 'CODECOPY',
                   'EXTCODECOPY'):
        if len(compustate.prev_memory) < 4096:
            trace_data['memory'] = \
                ''.join([encode_hex(ascii_chr(x)) for x
                          in compustate.prev_memory])
        else:
            trace_data['sha3memory'] = \
                encode_hex(utils.sha3(b''.join([ascii_chr(x) for
                                      x in compustate.prev_memory])))
    if compustate.prev_prev_op in ('SSTORE',) or compustate.steps == 0:
        trace_data['storage'] = ext.log_storage(msg.to)
    trace_data['gas'] = utils.to_string(compustate.prev_gas)
    trace_data['gas_cost'] = utils.to_string(compustate.prev_gas - compustate.gas)
    trace_data['fee'] = fee
    trace_data['inst'] = opcode
    trace_data['pc'] = utils.to_string(compustate.prev_pc)
    if compustate.steps == 0:
        trace_data['depth'] = msg.depth
        trace_data['address'] = msg.to
    trace_data['steps'] = compustate.steps
    trace_data['depth'] = msg.depth
    if op[:4] == 'PUSH':
        print(repr(pushcache)[0:50])
        trace_data['pushvalue'] = pushcache[compustate.prev_pc]
#    tracer.trace('vm', op=op, **trace_data)
    str = 'vm ' + repr(trace_data['steps'])+' '+repr(op)+repr(trace_data)
    print(str[0:50])
#    print('vm', op, trace_data)
    compustate.steps += 1
    compustate.prev_prev_op = op
コード例 #5
0
 def intrinsic_gas_used(self):
     num_zero_bytes = str_to_bytes(self.data).count(ascii_chr(0))
     num_non_zero_bytes = len(self.data) - num_zero_bytes
     return (
             opcodes.GTXCOST +
             (opcodes.CREATE[3] if not self.to else 0) +
             opcodes.GTXDATAZERO * num_zero_bytes +
             opcodes.GTXDATANONZERO * num_non_zero_bytes +
             (opcodes.GTXXSHARDCOST if self.is_cross_shard() else 0)
     )
コード例 #6
0
    def ecies_encrypt(cls, data, raw_pubkey, shared_mac_data=''):
        """
        ECIES Encrypt, where P = recipient public key is:
        1) generate r = random value
        2) generate shared-secret = kdf( ecdhAgree(r, P) )
        3) generate R = rG [same op as generating a public key]
        4) send 0x04 || R || AsymmetricEncrypt(shared-secret, plaintext) || tag


        currently used by go:
        ECIES_AES128_SHA256 = &ECIESParams{
            Hash: sha256.New,
            hashAlgo: crypto.SHA256,
            Cipher: aes.NewCipher,
            BlockSize: aes.BlockSize,
            KeyLen: 16,
            }

        """
        # 1) generate r = random value
        ephem = cls(None)

        # 2) generate shared-secret = kdf( ecdhAgree(r, P) )
        key_material = ephem.raw_get_ecdh_key(pubkey_x=raw_pubkey[:32],
                                              pubkey_y=raw_pubkey[32:])
        assert len(key_material) == 32
        key = eciesKDF(key_material, 32)
        assert len(key) == 32
        key_enc, key_mac = key[:16], key[16:]

        key_mac = hashlib.sha256(key_mac).digest()  # !!!
        assert len(key_mac) == 32
        # 3) generate R = rG [same op as generating a public key]
        ephem_pubkey = ephem.raw_pubkey

        # encrypt
        iv = pyelliptic.Cipher.gen_IV(cls.ecies_ciphername)
        assert len(iv) == 16
        ctx = pyelliptic.Cipher(key_enc, iv, 1, cls.ecies_ciphername)
        ciphertext = ctx.ciphering(data)
        assert len(ciphertext) == len(data)

        # 4) send 0x04 || R || AsymmetricEncrypt(shared-secret, plaintext)
        #    || tag
        msg = rlp_utils.ascii_chr(0x04) + ephem_pubkey + iv + ciphertext

        # the MAC of a message (called the tag) as per SEC 1, 3.5.
        tag = pyelliptic.hmac_sha256(
            key_mac, msg[1 + 64:] + rlp_utils.str_to_bytes(shared_mac_data))
        assert len(tag) == 32
        msg += tag

        assert len(msg) == 1 + 64 + 16 + 32 + len(data) == 113 + len(data)
        assert len(msg) - cls.ecies_encrypt_overhead_length == len(data)
        return msg
コード例 #7
0
ファイル: trie.py プロジェクト: Feretrius/pyethereum
def nibbles_to_bin(nibbles):
    if any(x > 15 or x < 0 for x in nibbles):
        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
コード例 #8
0
def nibbles_to_bin(nibbles):
    if any(x > 15 or x < 0 for x in nibbles):
        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
コード例 #9
0
 def cb(res, gas, dat, databytes):
     if res:
         b = extract_bytes(dat, 0, databytes)
         block.set_code(callstack[-1].to, ''.join([ascii_chr(x) for x in b]))
         res = utils.coerce_to_int(callstack[-1].to)
     else:
         if tx.sender != callstack[-1].sender:
             block.decrement_nonce(callstack[-1].sender)
         block.del_account(callstack[-1].to)
     callstack[-2].compustate.stack.append(res)
     callstack[-2].compustate.gas = gas
コード例 #10
0
def subnib_to_binstr(nibblearr):
	# Used in situation, when you take nibblearr not from the beginning, thus lost 1 char with metadata
	if len(nibblearr) % 2:
		nibblearr = [HEX_SEQUENCE_ODD] + nibblearr
	else:
		nibblearr = [HEX_SEQUENCE_EVEN, 0] + nibblearr
	binstring = b''
	for i in range(0, len(nibblearr), 2):
		if nibblearr[i] > 15 or nibblearr[i] < 0:
			raise Exception("invalid nibblearr[" + str(i) + "] =", nibblearr[i])
		if nibblearr[i + 1] > 15 or nibblearr[i + 1] < 0:
			raise Exception("invalid nibblearr[" + str(i+1) + "] =", nibblearr[i+1])
		binstring += ascii_chr(16 * nibblearr[i] + nibblearr[i + 1])
	return binstring
コード例 #11
0
def pack_nibbles(nibbles):
    if nibbles[-1:] == [NIBBLE_TERMINATOR]:
        flags = 2
        nibbles = nibbles[:-1]
    else:
        flags = 0
    oddlen = len(nibbles) % 2
    flags |= oddlen
    if oddlen:
        nibbles = [flags] + nibbles
    else:
        nibbles = [flags, 0] + nibbles
    o = b''
    for i in range(0, len(nibbles), 2):
        o += ascii_chr(16 * nibbles[i] + nibbles[i + 1])
    return o
コード例 #12
0
def subnib_to_binstr(nibblearr):
    # Used in situation, when you take nibblearr not from the beginning, thus lost 1 char with metadata
    if len(nibblearr) % 2:
        nibblearr = [HEX_SEQUENCE_ODD] + nibblearr
    else:
        nibblearr = [HEX_SEQUENCE_EVEN, 0] + nibblearr
    binstring = b''
    for i in range(0, len(nibblearr), 2):
        if nibblearr[i] > 15 or nibblearr[i] < 0:
            raise Exception("invalid nibblearr[" + str(i) + "] =",
                            nibblearr[i])
        if nibblearr[i + 1] > 15 or nibblearr[i + 1] < 0:
            raise Exception("invalid nibblearr[" + str(i + 1) + "] =",
                            nibblearr[i + 1])
        binstring += ascii_chr(16 * nibblearr[i] + nibblearr[i + 1])
    return binstring
コード例 #13
0
def proc_ecrecover(ext, msg):
    #print('ecrecover proc', msg.gas)
    OP_GAS = opcodes.GECRECOVER
    gas_cost = OP_GAS
    if msg.gas < gas_cost:
        return 0, 0, []
    b = [0] * 32
    msg.data.extract_copy(b, 0, 0, 32)
    h = ''.join([ascii_chr(x) for x in b])
    v = msg.data.extract32(32)
    r = msg.data.extract32(64)
    s = msg.data.extract32(96)
    if r >= bitcoin.N or s >= bitcoin.P or v < 27 or v > 28:
        return 1, msg.gas - opcodes.GECRECOVER, [0] * 32
    pub = bitcoin.encode_pubkey(bitcoin.ecdsa_raw_recover(h, (v, r, s)), 'bin')
    o = [0] * 12 + [safe_ord(x) for x in utils.sha3(pub[1:])[-20:]]
    return 1, msg.gas - gas_cost, o
コード例 #14
0
ファイル: rlpxcipher.py プロジェクト: jamesqiuhaorna/hgfrr
    def create_auth_message(self,
                            remote_pubkey,
                            ephemeral_privkey=None,
                            nonce=None):
        """
        1. initiator generates ecdhe-random and nonce and creates auth
        2. initiator connects to remote and sends auth

        New:
        E(remote-pubk,
            S(ephemeral-privk, ecdh-shared-secret ^ nonce) ||
            H(ephemeral-pubk) || pubk || nonce || 0x0
        )
        Known:
        E(remote-pubk,
            S(ephemeral-privk, token ^ nonce) || H(ephemeral-pubk) || pubk || nonce || 0x1)
        """
        assert self.is_initiator
        if not self.ecc.is_valid_key(remote_pubkey):
            raise InvalidKeyError('invalid remote pubkey')
        self.remote_pubkey = remote_pubkey

        ecdh_shared_secret = self.ecc.get_ecdh_key(remote_pubkey)
        token = ecdh_shared_secret
        flag = 0x0
        self.initiator_nonce = nonce or sha3(
            ienc(random.randint(0, 2**256 - 1)))
        assert len(self.initiator_nonce) == 32

        token_xor_nonce = sxor(token, self.initiator_nonce)
        assert len(token_xor_nonce) == 32

        ephemeral_pubkey = self.ephemeral_ecc.raw_pubkey
        assert len(ephemeral_pubkey) == 512 / 8
        if not self.ecc.is_valid_key(ephemeral_pubkey):
            raise InvalidKeyError('invalid ephemeral pubkey')

        # S(ephemeral-privk, ecdh-shared-secret ^ nonce)
        S = self.ephemeral_ecc.sign(token_xor_nonce)
        assert len(S) == 65

        # S || H(ephemeral-pubk) || pubk || nonce || 0x0
        auth_message = S + sha3(ephemeral_pubkey) + self.ecc.raw_pubkey + \
            self.initiator_nonce + ascii_chr(flag)
        assert len(auth_message) == 65 + 32 + 64 + 32 + 1 == 194
        return auth_message
コード例 #15
0
 def OP_CREATE():
     value, mstart, msz = stk.pop(), stk.pop(), stk.pop()
     if not mem_extend(mem, msgtop.compustate, '', mstart, msz):
         return drop(OUT_OF_GAS)
     if block.get_balance(msgtop.to) >= value:
         sender = decode_hex(msgtop.to) if len(msgtop.to) == 40 else msgtop.to
         block.increment_nonce(msgtop.to)
         data = [0] * ((msz >> 5) + 1)
         copy32(mem, data, mstart, 0, msz)
         create_msg = Message(msgtop.to, '', value, gaz() - 100, data, msz)
         msgtop.compustate.gas -= gaz() - 100
         nonce = utils.encode_int(block.get_nonce(msgtop.to) - 1)
         create_msg.to = encode_hex(utils.sha3(rlp.encode([sender, nonce]))[12:])
         special[0] = 'create'
         special[1] = create_msg
         special[2] = ''.join([ascii_chr(x) for x in extract_bytes(data, 0, msz)])
     else:
         stk.append(0)
コード例 #16
0
ファイル: compress.py プロジェクト: Feretrius/pyethereum
def compress(data):
    o = b''
    i = 0
    while i < len(data):
        if int_to_bytes(data[i]) == b'\xfe':
            o += b'\xfe\x00'
        elif data[i:i + 32] == NULLSHA3:
            o += b'\xfe\x01'
            i += 31
        elif data[i:i + 2] == b'\x00\x00':
            p = 2
            while p < 255 and i + p < len(data) and int_to_bytes(data[i + p]) == b'':
                p += 1
            o += b'\xfe' + ascii_chr(p)
            i += p - 1
        else:
            o += int_to_bytes(data[i])
        i += 1
    return o
コード例 #17
0
def compress(data):
    o = b''
    i = 0
    while i < len(data):
        if int_to_bytes(data[i]) == b'\xfe':
            o += b'\xfe\x00'
        elif data[i:i + 32] == NULLSHA3:
            o += b'\xfe\x01'
            i += 31
        elif data[i:i + 2] == b'\x00\x00':
            p = 2
            while p < 255 and i + \
                    p < len(data) and int_to_bytes(data[i + p]) == b'\x00':
                p += 1
            o += b'\xfe' + ascii_chr(p)
            i += p - 1
        else:
            o += int_to_bytes(data[i])
        i += 1
    return o
コード例 #18
0
ファイル: utils.py プロジェクト: shapirolab/epichain
def ecrecover_to_pub(rawhash, v, r, s):
    if coincurve and hasattr(coincurve, "PublicKey"):
        try:
            pk = coincurve.PublicKey.from_signature_and_message(
                zpad(bytearray_to_bytestr(int_to_32bytearray(r)), 32) + zpad(bytearray_to_bytestr(int_to_32bytearray(s)), 32) +
                ascii_chr(v - 27),
                rawhash,
                hasher=None,
            )
            pub = pk.format(compressed=False)[1:]
        except BaseException:
            pub = b"\x00" * 64
    else:
        result = ecdsa_raw_recover(rawhash, (v, r, s))
        if result:
            x, y = result
            pub = encode_int32(x) + encode_int32(y)
        else:
            raise ValueError('Invalid VRS')
    assert len(pub) == 64
    return pub
コード例 #19
0
def ecrecover_to_pub(rawhash, v, r, s):
    """
    Performs Solidity-like ecrecover.

    Arguments:
    - rawhash
    - v, r, s: Parts of the signature

    Returns the public key of the signer.
    """
    try:
        pk = coincurve.PublicKey.from_signature_and_message(
            zpad(bytes(int_to_32bytearray(r)), 32) +
            zpad(bytes(int_to_32bytearray(s)), 32) + ascii_chr(v - 27),
            rawhash,
            hasher=None,
        )
        pub = pk.format(compressed=False)[1:]
    except BaseException:
        pub = b"\x00" * 64
    assert len(pub) == 64
    return pub
コード例 #20
0
def pack_nibbles(nibbles):
    """pack nibbles to binary

    :param nibbles: a nibbles sequence. may have a terminator
    """

    if nibbles[-1:] == [NIBBLE_TERMINATOR]:
        flags = 2
        nibbles = nibbles[:-1]
    else:
        flags = 0

    oddlen = len(nibbles) % 2
    flags |= oddlen  # set lowest bit if odd number of nibbles
    if oddlen:
        nibbles = [flags] + nibbles
    else:
        nibbles = [flags, 0] + nibbles
    o = b''
    for i in range(0, len(nibbles), 2):
        o += ascii_chr(16 * nibbles[i] + nibbles[i + 1])
    return o
コード例 #21
0
ファイル: trie.py プロジェクト: Feretrius/pyethereum
def pack_nibbles(nibbles):
    """pack nibbles to binary

    :param nibbles: a nibbles sequence. may have a terminator
    """

    if nibbles[-1:] == [NIBBLE_TERMINATOR]:
        flags = 2
        nibbles = nibbles[:-1]
    else:
        flags = 0

    oddlen = len(nibbles) % 2
    flags |= oddlen   # set lowest bit if odd number of nibbles
    if oddlen:
        nibbles = [flags] + nibbles
    else:
        nibbles = [flags, 0] + nibbles
    o = b''
    for i in range(0, len(nibbles), 2):
        o += ascii_chr(16 * nibbles[i] + nibbles[i + 1])
    return o
コード例 #22
0
ファイル: tester.py プロジェクト: vaizguy/pyethereum
 def _send(self,
           sender,
           to,
           value,
           evmdata='',
           output=None,
           funid=None,
           abi=None,
           profiling=0):
     if funid is not None or abi is not None:
         raise Exception("Send with funid+abi is deprecated. Please use"
                         " the abi_contract mechanism")
     tm, g = time.time(), self.block.gas_used
     sendnonce = self.block.get_nonce(u.privtoaddr(sender))
     tx = t.Transaction(sendnonce, 1, gas_limit, to, value, evmdata)
     self.last_tx = tx
     tx.sign(sender)
     recorder = LogRecorder() if profiling > 1 else None
     (s, o) = pb.apply_transaction(self.block, tx)
     if not s:
         raise Exception("Transaction failed")
     out = {"output": o}
     if profiling > 0:
         zero_bytes = tx.data.count(ascii_chr(0))
         non_zero_bytes = len(tx.data) - zero_bytes
         intrinsic_gas_used = opcodes.GTXDATAZERO * zero_bytes + \
             opcodes.GTXDATANONZERO * non_zero_bytes
         ntm, ng = time.time(), self.block.gas_used
         out["time"] = ntm - tm
         out["gas"] = ng - g - intrinsic_gas_used
     if profiling > 1:
         trace = recorder.pop_records()
         ops = [x['op'] for x in trace if x['event'] == 'vm']
         opdict = {}
         for op in ops:
             opdict[op] = opdict.get(op, 0) + 1
         out["ops"] = opdict
     return out
コード例 #23
0
ファイル: processblock.py プロジェクト: 4gn3s/pyethereum
def intrinsic_gas_used(tx):
    num_zero_bytes = str_to_bytes(tx.data).count(ascii_chr(0))
    num_non_zero_bytes = len(tx.data) - num_zero_bytes
    return (opcodes.GTXCOST
            + opcodes.GTXDATAZERO * num_zero_bytes
            + opcodes.GTXDATANONZERO * num_non_zero_bytes)
コード例 #24
0
ファイル: vm.py プロジェクト: vaizguy/pyethereum
 def extract_all(self):
     d = self.data[self.offset:self.offset + self.size]
     d += [0] * (self.size - len(d))
     return b''.join([ascii_chr(x) for x in d])
コード例 #25
0
ファイル: vm.py プロジェクト: vaizguy/pyethereum
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

    codelen = len(processed_code)

    s = time.time()
    op = None

    while 1:
        # print 'op: ', op, time.time() - s
        # s = time.time()
        # stack size limit error
        if compustate.pc >= codelen:
            return peaceful_exit('CODE OUT OF RANGE', compustate.gas, [])

        op, in_args, out_args, fee, opcode, pushval = \
            processed_code[compustate.pc]

        # out of gas error
        if fee > compustate.gas:
            return vm_exception('OUT OF GAS')

        # empty stack error
        if in_args > len(compustate.stack):
            return vm_exception('INSUFFICIENT STACK',
                                op=op,
                                needed=to_string(in_args),
                                available=to_string(len(compustate.stack)))

        if len(compustate.stack) - in_args + out_args > 1024:
            return vm_exception('STACK SIZE LIMIT EXCEEDED',
                                op=op,
                                pre_height=to_string(len(compustate.stack)))

        # Apply operation
        compustate.gas -= fee
        compustate.pc += 1

        if trace_vm:
            """
            This diverges from normal logging, as we use the logging namespace
            only to decide which features get logged in 'eth.vm.op'
            i.e. tracing can not be activated by activating a sub like 'eth.vm.op.stack'
            """
            trace_data = {}
            if log_vm_op_stack.is_active():
                trace_data['stack'] = list(
                    map(to_string, list(compustate.stack)))
            if log_vm_op_memory.is_active():
                trace_data['memory'] = \
                    b''.join([encode_hex(ascii_chr(x)) for x in compustate.memory])
            if log_vm_op_storage.is_active():
                trace_data['storage'] = ext.log_storage(msg.to)
            trace_data['gas'] = to_string(compustate.gas + fee)
            trace_data['pc'] = to_string(compustate.pc - 1)
            trace_data['op'] = op
            if op[:4] == 'PUSH':
                trace_data['pushvalue'] = pushval

            log_vm_op.trace('vm', **trace_data)

        # Invalid operation
        if op == 'INVALID':
            return vm_exception('INVALID OP', opcode=opcode)

        # Valid operations
        if 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 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 = b''.join(map(ascii_chr, 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':
                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(processed_code))
            elif 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(processed_code):
                        mem[start + i] = processed_code[s1 + i][4]
                    else:
                        mem[start + i] = 0
            elif op == 'GASPRICE':
                stk.append(ext.tx_gasprice)
            elif op == 'EXTCODESIZE':
                addr = utils.coerce_addr_to_hex(stk.pop() % 2**160)
                stk.append(len(ext.get_code(addr) or b''))
            elif 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 isinstance(extcode, str)
                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] = ord(extcode[s2 + i])
                    else:
                        mem[start + i] = 0
        elif opcode < 0x50:
            if op == 'BLOCKHASH':
                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')
                data = b''.join(map(ascii_chr, mem[s0:s0 + 32]))
                stk.append(utils.big_endian_to_int(data))
            elif 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 == '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':
                stk.append(ext.get_storage_data(msg.to, stk.pop()))
            elif 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
                ext.add_refund(
                    refund)  # adds neg gascost as a refund if below zero
                ext.set_storage_data(msg.to, s0, s1)
            elif op == 'JUMP':
                compustate.pc = stk.pop()
                opnew = processed_code[compustate.pc][0] if \
                    compustate.pc < len(processed_code) else 'STOP'
                if opnew != 'JUMPDEST':
                    return vm_exception('BAD JUMPDEST')
            elif op == 'JUMPI':
                s0, s1 = stk.pop(), stk.pop()
                if s1:
                    compustate.pc = s0
                    opnew = processed_code[compustate.pc][0] if \
                        compustate.pc < len(processed_code) else 'STOP'
                    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[:4] == 'PUSH':
            pushnum = int(op[4:])
            compustate.pc += pushnum
            stk.append(pushval)
        elif op[:3] == 'DUP':
            depth = int(op[3:])
            stk.append(stk[-depth])
        elif op[:4] == 'SWAP':
            depth = int(op[4:])
            temp = stk[-depth - 1]
            stk[-depth - 1] = 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 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(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 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 == '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')
            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 == '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')
            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 == '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 == 'SUICIDE':
            to = utils.encode_int(stk.pop())
            to = ((b'\x00' * (32 - len(to))) + to)[12:]
            xfer = ext.get_balance(msg.to)
            ext.set_balance(msg.to, 0)
            ext.set_balance(to, ext.get_balance(to) + xfer)
            ext.add_suicide(msg.to)
            # print('suiciding %s %s %d' % (msg.to, to, xfer))
            return 1, compustate.gas, []

        # this is slow!
        if verify_stack_after_op:
            for a in stk:
                assert is_numeric(a)
                assert a >= 0 and a < 2**256, (a, op, stk)
コード例 #26
0
ファイル: utils.py プロジェクト: shapiroisme/pyethereum
def int_to_addr(x):
    o = [""] * 20
    for i in range(20):
        o[19 - i] = ascii_chr(x & 0xFF)
        x >>= 8
    return b"".join(o)
コード例 #27
0
 def OP_SHA3():
     s0, s1 = stk.pop(), stk.pop()
     if not mem_extend(mem, msgtop.compustate, '', s0, s1):
         return drop(OUT_OF_GAS)
     data = ''.join([ascii_chr(x) for x in mem[s0: s0 + s1]])
     stk.append(utils.big_endian_to_int(utils.sha3(data)))
コード例 #28
0
import pytest
from rlp import SerializationError, utils
from rlp.sedes import big_endian_int, BigEndianInt

valid_data = (
    (256, b'\x01\x00'),
    (1024, b'\x04\x00'),
    (65535, b'\xff\xff'),
)

single_bytes = ((n, utils.ascii_chr(n)) for n in range(1, 256))

random_integers = (256, 257, 4839, 849302, 483290432, 483290483290482039482039,
                   48930248348219540325894323584235894327865439258743754893066)

negative_ints = (-1, -100, -255, -256, -2342423)


def test_neg():
    for n in negative_ints:
        with pytest.raises(SerializationError):
            big_endian_int.serialize(n)


def test_serialization():
    for n in random_integers:
        serial = big_endian_int.serialize(n)
        deserialized = big_endian_int.deserialize(serial)
        assert deserialized == n
        if n != 0:
            assert serial[0] != b'\x00'  # is not checked
コード例 #29
0
ファイル: rlpxcipher.py プロジェクト: jamesqiuhaorna/hgfrr
def sxor(s1, s2):
    "string xor"
    assert len(s1) == len(s2)
    return b''.join(
        ascii_chr(safe_ord(a) ^ safe_ord(b)) for a, b in zip(s1, s2))
コード例 #30
0
ファイル: fastvm.py プロジェクト: biblecoin/pybiblecoin
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')
コード例 #31
0
ファイル: vm.py プロジェクト: Aireed/pyethereum
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

    codelen = len(processed_code)

    s = time.time()
    op = None
    steps = 0
    _prevop = None  # for trace only

    while 1:
        # print('op: ', op, time.time() - s)
        # s = time.time()
        # stack size limit error
        if compustate.pc >= codelen:
            return peaceful_exit('CODE OUT OF RANGE', compustate.gas, [])

        op, in_args, out_args, fee, opcode, pushval = \
            processed_code[compustate.pc]

        # out of gas error
        if fee > compustate.gas:
            return vm_exception('OUT OF GAS')

        # empty stack error
        if in_args > len(compustate.stack):
            return vm_exception('INSUFFICIENT STACK',
                                op=op, needed=to_string(in_args),
                                available=to_string(len(compustate.stack)))

        if len(compustate.stack) - in_args + out_args > 1024:
            return vm_exception('STACK SIZE LIMIT EXCEEDED',
                                op=op,
                                pre_height=to_string(len(compustate.stack)))

        # Apply operation
        compustate.gas -= fee
        compustate.pc += 1

        if trace_vm:
            """
            This diverges from normal logging, as we use the logging namespace
            only to decide which features get logged in 'eth.vm.op'
            i.e. tracing can not be activated by activating a sub
            like 'eth.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'] = \
                        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 ('SSTORE', 'SLOAD') or steps == 0:
                trace_data['storage'] = ext.log_storage(msg.to)
            trace_data['gas'] = to_string(compustate.gas + fee)
            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['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=opcode)

        # Valid operations
        if 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 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 = b''.join(map(ascii_chr, 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':
                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(processed_code))
            elif 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(processed_code):
                        mem[start + i] = processed_code[s1 + i][4]
                    else:
                        mem[start + i] = 0
            elif op == 'GASPRICE':
                stk.append(ext.tx_gasprice)
            elif op == 'EXTCODESIZE':
                addr = utils.coerce_addr_to_hex(stk.pop() % 2**160)
                stk.append(len(ext.get_code(addr) or b''))
            elif 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 opcode < 0x50:
            if op == 'BLOCKHASH':
                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')
                data = b''.join(map(ascii_chr, mem[s0: s0 + 32]))
                stk.append(utils.big_endian_to_int(data))
            elif 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 == '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':
                stk.append(ext.get_storage_data(msg.to, stk.pop()))
            elif 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
                ext.add_refund(refund)  # adds neg gascost as a refund if below zero
                ext.set_storage_data(msg.to, s0, s1)
            elif op == 'JUMP':
                compustate.pc = stk.pop()
                opnew = processed_code[compustate.pc][0] if \
                    compustate.pc < len(processed_code) else 'STOP'
                if opnew != 'JUMPDEST':
                    return vm_exception('BAD JUMPDEST')
            elif op == 'JUMPI':
                s0, s1 = stk.pop(), stk.pop()
                if s1:
                    compustate.pc = s0
                    opnew = processed_code[compustate.pc][0] if \
                        compustate.pc < len(processed_code) else 'STOP'
                    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[:4] == 'PUSH':
            pushnum = int(op[4:])
            compustate.pc += pushnum
            stk.append(pushval)
        elif op[:3] == 'DUP':
            depth = int(op[3:])
            stk.append(stk[-depth])
        elif op[:4] == 'SWAP':
            depth = int(op[4:])
            temp = stk[-depth - 1]
            stk[-depth - 1] = 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 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 == '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 == '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 == 'CALLCODE' or op == 'DELEGATECALL':
            if op == '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
            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)
                if 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)
                elif op == 'DELEGATECALL':
                    return vm_exception('OPCODE INACTIVE')
                else:
                    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 == '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 == '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, []
コード例 #32
0
ファイル: vm.py プロジェクト: Aireed/pyethereum
 def extract_all(self):
     d = self.data[self.offset: self.offset + self.size]
     d += [0] * (self.size - len(d))
     return b''.join([ascii_chr(x) for x in d])
コード例 #33
0
    def _send(
            self,
            sender,
            to,
            value,
            evmdata='',
            funid=None,
            abi=None,  # pylint: disable=too-many-arguments
            profiling=0):
        # pylint: disable=too-many-locals

        if funid is not None or abi is not None:
            raise Exception(
                'Send with funid+abi is deprecated. Please use the abi_contract mechanism'
            )

        start_time = time.time()
        gas_used = self.block.gas_used

        sendnonce = self.block.get_nonce(privtoaddr(sender))
        transaction = transactions.Transaction(sendnonce, gas_price, gas_limit,
                                               to, value, evmdata)
        self.last_tx = transaction
        transaction.sign(sender)
        recorder = None

        if profiling > 1:
            recorder = LogRecorder(
                disable_other_handlers=True,
                log_config=TRACE_LVL_MAP[3],
            )

        try:
            (success,
             output) = processblock.apply_transaction(self.block, transaction)

            if not success:
                raise TransactionFailed()

            out = {
                'output': output,
            }

            if profiling > 0:
                zero_bytes_count = transaction.data.count(ascii_chr(0))
                non_zero_bytes_count = len(transaction.data) - zero_bytes_count

                zero_bytes_cost = opcodes.GTXDATAZERO * zero_bytes_count
                nonzero_bytes_cost = opcodes.GTXDATANONZERO * non_zero_bytes_count

                base_gas_cost = opcodes.GTXCOST
                intrinsic_gas_used = base_gas_cost + zero_bytes_cost + nonzero_bytes_cost

                out['time'] = time.time() - start_time
                out['gas'] = self.block.gas_used - gas_used - intrinsic_gas_used

            if profiling > 1:
                trace = recorder.pop_records()
                vm_operations = [
                    event['op'] for event in trace if event['event'] == 'vm'
                ]
                opdict = {}
                for operation in vm_operations:
                    opdict[operation] = opdict.get(operation, 0) + 1
                out['ops'] = opdict

            return out
        finally:
            # ensure LogRecorder has been disabled
            if recorder:
                recorder.pop_records()
コード例 #34
0
ファイル: tester.py プロジェクト: Aireed/pyethereum
    def _send(self, sender, to, value, evmdata='', funid=None, abi=None,  # pylint: disable=too-many-arguments
              profiling=0):
        # pylint: disable=too-many-locals

        if funid is not None or abi is not None:
            raise Exception(
                'Send with funid+abi is deprecated. Please use the abi_contract mechanism'
            )

        start_time = time.time()
        gas_used = self.block.gas_used

        sendnonce = self.block.get_nonce(privtoaddr(sender))
        transaction = transactions.Transaction(sendnonce, gas_price, gas_limit, to, value, evmdata)
        self.last_tx = transaction
        transaction.sign(sender)
        recorder = None

        if profiling > 1:
            recorder = LogRecorder(
                disable_other_handlers=True,
                log_config=TRACE_LVL_MAP[3],
            )

        try:
            (success, output) = processblock.apply_transaction(self.block, transaction)

            if not success:
                raise TransactionFailed()

            out = {
                'output': output,
            }

            if profiling > 0:
                zero_bytes_count = transaction.data.count(ascii_chr(0))
                non_zero_bytes_count = len(transaction.data) - zero_bytes_count

                zero_bytes_cost = opcodes.GTXDATAZERO * zero_bytes_count
                nonzero_bytes_cost = opcodes.GTXDATANONZERO * non_zero_bytes_count

                base_gas_cost = opcodes.GTXCOST
                intrinsic_gas_used = base_gas_cost + zero_bytes_cost + nonzero_bytes_cost

                out['time'] = time.time() - start_time
                out['gas'] = self.block.gas_used - gas_used - intrinsic_gas_used

            if profiling > 1:
                trace = recorder.pop_records()
                vm_operations = [
                    event['op']
                    for event in trace
                    if event['event'] == 'vm'
                ]
                opdict = {}
                for operation in vm_operations:
                    opdict[operation] = opdict.get(operation, 0) + 1
                out['ops'] = opdict

            return out
        finally:
            # ensure LogRecorder has been disabled
            if recorder:
                recorder.pop_records()
コード例 #35
0
def vm_execute(ext, msg, code):
    # precompute trace flag
    # if we trace vm, we're in slow mode anyway
    trace_vm = True #log_vm_op.is_active('trace')

    # Initialize stack, memory, program counter, etc
    compustate = Compustate(gas=msg.gas)
    stk = compustate.stack
    mem = compustate.memory

    # Compute
    jumpdest_mask, pushcache = preprocess_code(code)
    codelen = len(code)

    # For tracing purposes
    op = None
    _prevop = None
    steps = 0
    while compustate.pc < codelen:

        opcode = utils.safe_ord(code[compustate.pc])

        # Invalid operation
        if opcode not in opcodes.opcodes:
            return vm_exception('INVALID OP', opcode=opcode)

        op, in_args, out_args, fee = opcodes.opcodes[opcode]

        # Apply operation
        if trace_vm:
            compustate.reset_prev()
        compustate.gas -= fee
        compustate.pc += 1

        # Tracing
        if trace_vm:
            """
            This diverges from normal logging, as we use the logging namespace
            only to decide which features get logged in 'eth.vm.op'
            i.e. tracing can not be activated by activating a sub
            like 'eth.vm.op.stack'
            """
            trace_data = {}
            trace_data['gas'] = utils.to_string(compustate.gas + fee)
            trace_data['stack'] = list(map(utils.to_string, list(compustate.stack)))
            if _prevop in ('MLOAD', 'MSTORE', 'MSTORE8', 'SHA3', 'CALL',
                           'CALLCODE', 'CREATE', 'CALLDATACOPY', 'CODECOPY',
                           'EXTCODECOPY'):
                if len(compustate.memory) < 4096:
                    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['inst'] = opcode
            trace_data['pc'] = utils.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'] = pushcache[compustate.pc - 1]
            str = 'vm ' + repr(trace_data['steps'])+' '+repr(op)+repr(trace_data)
            print(str[0:200])
#            print('vm', op, trace_data)
            steps += 1
            _prevop = op

        # out of gas error
        if compustate.gas < 0:
            return vm_exception('OUT OF GAS')

        # empty stack error
        if in_args > len(compustate.stack):
            return vm_exception('INSUFFICIENT STACK',
                                op=op, needed=utils.to_string(in_args),
                                available=utils.to_string(len(compustate.stack)))

        # overfull stack error
        if len(compustate.stack) - in_args + out_args > 1024:
            return vm_exception('STACK SIZE LIMIT EXCEEDED',
                                op=op,
                                pre_height=utils.to_string(len(compustate.stack)))

        # Valid operations
        # Pushes first because they are very frequent
        if 0x60 <= opcode <= 0x7f:
            stk.append(pushcache[compustate.pc - 1])
            # Move 1 byte forward for 0x60, up to 32 bytes for 0x7f
            compustate.pc += opcode - 0x5f
        # Arithmetic
        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
                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)
        # Comparisons
        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)
        # SHA3 and environment info
        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 = utils.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 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(codelen)
            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 < codelen:
                        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[dstart: dstart + size]
            elif op == 'RETURNDATASIZE':
                stk.append(len(compustate.last_returned))
            elif op == 'GASPRICE':
                stk.append(ext.tx_gasprice)
            elif op == 'EXTCODESIZE':
                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 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
        # Block info
        elif opcode < 0x50:
            if op == 'BLOCKHASH':
                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)
        # VM state manipulations
        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 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()
                if compustate.pc >= codelen or not (
                        (1 << compustate.pc) & jumpdest_mask):
                    return vm_exception('BAD JUMPDEST')
            elif op == 'JUMPI':
                s0, s1 = stk.pop(), stk.pop()
                if s1:
                    compustate.pc = s0
                    if compustate.pc >= codelen or not (
                            (1 << compustate.pc) & jumpdest_mask):
                        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
        # DUPn (eg. DUP1: a b c -> a b c c, DUP3: a b c -> a b c a)
        elif op[:3] == 'DUP':
            # 0x7f - opcode is a negative number, -1 for 0x80 ... -16 for 0x8f
            stk.append(stk[0x7f - opcode])
        # SWAPn (eg. SWAP1: a b c d -> a b d c, SWAP3: a b c d -> d b c a)
        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
        # Logs (aka "events")
        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 = utils.bytearray_to_bytestr(mem[mstart: mstart + msz])
            ext.log(msg.to, topics, data)
            # print('LOG', msg.to, topics, list(map(ord, data)))
        # Create a new contract
        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
                ingas = all_but_1n(ingas, opcodes.CALL_CHILD_LIMIT_DENOM)
                create_msg = Message(msg.to, b'', value, ingas, cd, msg.depth + 1)
                o, gas, data = ext.create(create_msg)
                if o:
                    stk.append(utils.coerce_to_int(data))
                    compustate.last_returned = bytearray(b'')
                else:
                    stk.append(0)
                    compustate.last_returned = bytearray(data)
                compustate.gas = compustate.gas - ingas + gas
            else:
                stk.append(0)
                compustate.last_returned = bytearray(b'')
        # Calls
        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 and op == 'CALL':
                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 various factors
            extra_gas = 0
            # Creating a new account
            if op == 'CALL' and not ext.account_exists(to) and (value > 0):
                extra_gas += opcodes.GCALLNEWACCOUNT
            # Value transfer
            if value > 0:
                extra_gas += opcodes.GCALLVALUETRANSFER
            # Cost increased from 40 to 700 in Tangerine Whistle
            extra_gas += opcodes.CALL_SUPPLEMENTAL_GAS
            # Compute child gas limit
            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))
            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)
                compustate.last_returned = bytearray(b'')
            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 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 == 'STATICCALL':
                    call_msg = Message(msg.to, to, value, submsg_gas, cd,
                                       msg.depth + 1, code_address=to, static=True)
                elif op in ('DELEGATECALL', 'STATICCALL'):
                    return vm_exception('OPCODE %s INACTIVE' % op)
                elif op == 'CALLCODE':
                    call_msg = Message(msg.to, msg.to, value, submsg_gas, cd,
                                       msg.depth + 1, code_address=to, static=msg.static)
                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)
        # Return opcode
        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])
        # Revert opcode (Metropolis)
        elif op == 'REVERT':
            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])
        # SUICIDE opcode (also called SELFDESTRUCT)
        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)
            extra_gas = opcodes.SUICIDE_SUPPLEMENTAL_GAS + \
                (not ext.account_exists(to)) * (xfer > 0) * 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 peaceful_exit('SUICIDED', compustate.gas, [])

#        if trace_vm:
#            vm_trace(ext, msg, compustate, opcode, pushcache)

    if trace_vm:
        compustate.reset_prev()
        vm_trace(ext, msg, compustate, 0, None)
    return peaceful_exit('CODE OUT OF RANGE', compustate.gas, [])
コード例 #36
0
ファイル: testutils.py プロジェクト: Aireed/pyethereum
def run_vm_test(params, mode, profiler=None):
    pre = params['pre']
    exek = params['exec']
    env = params['env']
    if 'previousHash' not in env:
        env['previousHash'] = encode_hex(db_env.config['GENESIS_PREVHASH'])

    assert set(env.keys()) == set(['currentGasLimit', 'currentTimestamp',
                                   'previousHash', 'currentCoinbase',
                                   'currentDifficulty', 'currentNumber'])
    # setup env
    header = blocks.BlockHeader(
        prevhash=decode_hex(env['previousHash']),
        number=parse_int_or_hex(env['currentNumber']),
        coinbase=decode_hex(env['currentCoinbase']),
        difficulty=parse_int_or_hex(env['currentDifficulty']),
        gas_limit=parse_int_or_hex(env['currentGasLimit']),
        timestamp=parse_int_or_hex(env['currentTimestamp']))

    blk = blocks.Block(header, env=db_env)

    # setup state
    for address, h in list(pre.items()):
        assert len(address) == 40
        address = decode_hex(address)
        assert set(h.keys()) == set(['code', 'nonce', 'balance', 'storage'])
        blk.set_nonce(address, parse_int_or_hex(h['nonce']))
        blk.set_balance(address, parse_int_or_hex(h['balance']))
        blk.set_code(address, decode_hex(h['code'][2:]))
        for k, v in h['storage'].items():
            blk.set_storage_data(address,
                                 utils.big_endian_to_int(decode_hex(k[2:])),
                                 utils.big_endian_to_int(decode_hex(v[2:])))

    # execute transactions
    sender = decode_hex(exek['caller'])  # a party that originates a call
    recvaddr = decode_hex(exek['address'])
    nonce = blk._get_acct_item(sender, 'nonce')
    gasprice = parse_int_or_hex(exek['gasPrice'])
    startgas = parse_int_or_hex(exek['gas'])
    value = parse_int_or_hex(exek['value'])
    data = decode_hex(exek['data'][2:])

    # bypass gas check in tx initialization by temporarily increasing startgas
    num_zero_bytes = str_to_bytes(data).count(ascii_chr(0))
    num_non_zero_bytes = len(data) - num_zero_bytes
    intrinsic_gas = (opcodes.GTXCOST + opcodes.GTXDATAZERO * num_zero_bytes +
                     opcodes.GTXDATANONZERO * num_non_zero_bytes)
    startgas += intrinsic_gas
    tx = transactions.Transaction(nonce=nonce, gasprice=gasprice, startgas=startgas,
                                  to=recvaddr, value=value, data=data)
    tx.startgas -= intrinsic_gas
    tx.sender = sender

    # capture apply_message calls
    apply_message_calls = []
    orig_apply_msg = pb.apply_msg

    ext = pb.VMExt(blk, tx)

    def msg_wrapper(msg):
        hexdata = encode_hex(msg.data.extract_all())
        apply_message_calls.append(dict(gasLimit=to_string(msg.gas),
                                        value=to_string(msg.value),
                                        destination=encode_hex(msg.to),
                                        data=b'0x' + hexdata))
        return 1, msg.gas, b''

    def create_wrapper(msg):
        sender = decode_hex(msg.sender) if \
            len(msg.sender) == 40 else msg.sender
        nonce = utils.encode_int(ext._block.get_nonce(msg.sender))
        addr = utils.sha3(rlp.encode([sender, nonce]))[12:]
        hexdata = encode_hex(msg.data.extract_all())
        apply_message_calls.append(dict(gasLimit=to_string(msg.gas),
                                        value=to_string(msg.value),
                                        destination=b'', data=b'0x' + hexdata))
        return 1, msg.gas, addr

    ext.msg = msg_wrapper
    ext.create = create_wrapper

    def blkhash(n):
        if n >= ext.block_number or n < ext.block_number - 256:
            return b''
        else:
            return utils.sha3(to_string(n))

    ext.block_hash = blkhash

    msg = vm.Message(tx.sender, tx.to, tx.value, tx.startgas,
                     vm.CallData([safe_ord(x) for x in tx.data]))
    code = decode_hex(exek['code'][2:])
    time_pre = time.time()
    if profiler:
        profiler.enable()
    success, gas_remained, output = vm.vm_execute(ext, msg, code)
    if profiler:
        profiler.disable()
    pb.apply_msg = orig_apply_msg
    blk.commit_state()
    for s in blk.suicides:
        blk.del_account(s)
    time_post = time.time()

    """
     generally expected that the test implementer will read env, exec and pre
     then check their results against gas, logs, out, post and callcreates.
     If an exception is expected, then latter sections are absent in the test.
     Since the reverting of the state is not part of the VM tests.
     """

    params2 = copy.deepcopy(params)

    if success:
        params2['callcreates'] = apply_message_calls
        params2['out'] = b'0x' + encode_hex(b''.join(map(ascii_chr, output)))
        params2['gas'] = to_string(gas_remained)
        params2['logs'] = [log.to_dict() for log in blk.logs]
        params2['post'] = blk.to_dict(with_state=True)['state']

    if mode == FILL:
        return params2
    elif mode == VERIFY:
        if not success:
            assert 'post' not in params, 'failed, but expected to succeed'

        params1 = copy.deepcopy(params)
        shouldbe, reallyis = params1.get('post', None), params2.get('post', None)
        compare_post_states(shouldbe, reallyis)

        def normalize_value(k, p):
            if k in p:
                if k == 'gas':
                    return parse_int_or_hex(p[k])
                elif k == 'callcreates':
                    return list(map(callcreate_standard_form, p[k]))
                else:
                    return utils.to_string(k)
            return None

        for k in ['pre', 'exec', 'env', 'callcreates',
                  'out', 'gas', 'logs']:
            shouldbe = normalize_value(k, params1)
            reallyis = normalize_value(k, params2)
            if shouldbe != reallyis:
                raise Exception("Mismatch: " + k + ':\n shouldbe %r\n reallyis %r' %
                                (shouldbe, reallyis))
    elif mode == TIME:
        return time_post - time_pre
コード例 #37
0
def random_string(length):
    return ''.join([ascii_chr(random.randint(0, 255)) for _ in range(length)])
コード例 #38
0
def int_to_addr(x):
    o = [b''] * 20
    for i in range(20):
        o[19 - i] = ascii_chr(x & 0xff)
        x >>= 8
    return b''.join(o)
コード例 #39
0
def intrinsic_gas_used(tx):
    num_zero_bytes = str_to_bytes(tx.data).count(ascii_chr(0))
    num_non_zero_bytes = len(tx.data) - num_zero_bytes
    return (opcodes.GTXCOST + opcodes.GTXDATAZERO * num_zero_bytes +
            opcodes.GTXDATANONZERO * num_non_zero_bytes)
コード例 #40
0
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

    s = time.time()
    op = None
    steps = 0
    _prevop = None  # for trace only

    while 1:
      # 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 'eth.vm.op'
            i.e. tracing can not be activated by activating a sub
            like 'eth.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
                ext.add_refund(refund)  # adds neg gascost as a refund if below zero
                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, []
コード例 #41
0
ファイル: testutils.py プロジェクト: zebbra2014/pyethereum
def run_vm_test(params, mode, profiler=None):
    pre = params['pre']
    exek = params['exec']
    env = params['env']
    if 'previousHash' not in env:
        env['previousHash'] = encode_hex(db_env.config['GENESIS_PREVHASH'])

    assert set(env.keys()) == set([
        'currentGasLimit', 'currentTimestamp', 'previousHash',
        'currentCoinbase', 'currentDifficulty', 'currentNumber'
    ])
    # setup env
    header = blocks.BlockHeader(
        prevhash=decode_hex(env['previousHash']),
        number=parse_int_or_hex(env['currentNumber']),
        coinbase=decode_hex(env['currentCoinbase']),
        difficulty=parse_int_or_hex(env['currentDifficulty']),
        gas_limit=parse_int_or_hex(env['currentGasLimit']),
        timestamp=parse_int_or_hex(env['currentTimestamp']))
    blk = blocks.Block(header, env=db_env)

    # setup state
    for address, h in list(pre.items()):
        assert len(address) == 40
        address = decode_hex(address)
        assert set(h.keys()) == set(['code', 'nonce', 'balance', 'storage'])
        blk.set_nonce(address, parse_int_or_hex(h['nonce']))
        blk.set_balance(address, parse_int_or_hex(h['balance']))
        blk.set_code(address, decode_hex(h['code'][2:]))
        for k, v in h['storage'].items():
            blk.set_storage_data(address,
                                 utils.big_endian_to_int(decode_hex(k[2:])),
                                 utils.big_endian_to_int(decode_hex(v[2:])))

    # execute transactions
    sender = decode_hex(exek['caller'])  # a party that originates a call
    recvaddr = decode_hex(exek['address'])
    nonce = blk._get_acct_item(sender, 'nonce')
    gasprice = parse_int_or_hex(exek['gasPrice'])
    startgas = parse_int_or_hex(exek['gas'])
    value = parse_int_or_hex(exek['value'])
    data = decode_hex(exek['data'][2:])

    # bypass gas check in tx initialization by temporarily increasing startgas
    num_zero_bytes = str_to_bytes(data).count(ascii_chr(0))
    num_non_zero_bytes = len(data) - num_zero_bytes
    intrinsic_gas = (opcodes.GTXCOST + opcodes.GTXDATAZERO * num_zero_bytes +
                     opcodes.GTXDATANONZERO * num_non_zero_bytes)
    startgas += intrinsic_gas
    tx = transactions.Transaction(nonce=nonce,
                                  gasprice=gasprice,
                                  startgas=startgas,
                                  to=recvaddr,
                                  value=value,
                                  data=data)
    tx.startgas -= intrinsic_gas
    tx.sender = sender

    # capture apply_message calls
    apply_message_calls = []
    orig_apply_msg = pb.apply_msg

    ext = pb.VMExt(blk, tx)

    def msg_wrapper(msg):
        hexdata = encode_hex(msg.data.extract_all())
        apply_message_calls.append(
            dict(gasLimit=to_string(msg.gas),
                 value=to_string(msg.value),
                 destination=encode_hex(msg.to),
                 data=b'0x' + hexdata))
        return 1, msg.gas, b''

    def create_wrapper(msg):
        sender = decode_hex(msg.sender) if \
            len(msg.sender) == 40 else msg.sender
        nonce = utils.encode_int(ext._block.get_nonce(msg.sender))
        addr = utils.sha3(rlp.encode([sender, nonce]))[12:]
        hexdata = encode_hex(msg.data.extract_all())
        apply_message_calls.append(
            dict(gasLimit=to_string(msg.gas),
                 value=to_string(msg.value),
                 destination=b'',
                 data=b'0x' + hexdata))
        return 1, msg.gas, addr

    ext.msg = msg_wrapper
    ext.create = create_wrapper

    def blkhash(n):
        if n >= ext.block_number or n < ext.block_number - 256:
            return b''
        else:
            return utils.sha3(to_string(n))

    ext.block_hash = blkhash

    msg = vm.Message(tx.sender, tx.to, tx.value, tx.startgas,
                     vm.CallData([safe_ord(x) for x in tx.data]))
    code = decode_hex(exek['code'][2:])
    time_pre = time.time()
    if profiler:
        profiler.enable()
    success, gas_remained, output = vm.vm_execute(ext, msg, code)
    if profiler:
        profiler.disable()
    pb.apply_msg = orig_apply_msg
    blk.commit_state()
    for s in blk.suicides:
        blk.del_account(s)
    time_post = time.time()
    """
     generally expected that the test implementer will read env, exec and pre
     then check their results against gas, logs, out, post and callcreates.
     If an exception is expected, then latter sections are absent in the test.
     Since the reverting of the state is not part of the VM tests.
     """

    params2 = copy.deepcopy(params)

    if success:
        params2['callcreates'] = apply_message_calls
        params2['out'] = b'0x' + encode_hex(b''.join(map(ascii_chr, output)))
        params2['gas'] = to_string(gas_remained)
        params2['logs'] = [log.to_dict() for log in blk.logs]
        params2['post'] = blk.to_dict(with_state=True)['state']

    if mode == FILL:
        return params2
    elif mode == VERIFY:
        if not success:
            assert 'post' not in params, 'failed, but expected to succeed'

        params1 = copy.deepcopy(params)
        shouldbe, reallyis = params1.get('post',
                                         None), params2.get('post', None)
        compare_post_states(shouldbe, reallyis)

        def normalize_value(k, p):
            if k in p:
                if k == 'gas':
                    return parse_int_or_hex(p[k])
                elif k == 'callcreates':
                    return list(map(callcreate_standard_form, p[k]))
                else:
                    return utils.to_string(k)
            return None

        for k in ['pre', 'exec', 'env', 'callcreates', 'out', 'gas', 'logs']:
            shouldbe = normalize_value(k, params1)
            reallyis = normalize_value(k, params2)
            if shouldbe != reallyis:
                raise Exception("Mismatch: " + k +
                                ':\n shouldbe %r\n reallyis %r' %
                                (shouldbe, reallyis))
    elif mode == TIME:
        return time_post - time_pre
コード例 #42
0
ファイル: test_db.py プロジェクト: Feretrius/pyethereum
def random_string(length):
    return ''.join([ascii_chr(random.randint(0, 255)) for _ in range(length)])
コード例 #43
0
ファイル: ethereum_utils.py プロジェクト: vadim-di/ethjsonrpc
def int_to_addr(x):
    o = [b''] * 20
    for i in range(20):
        o[19 - i] = ascii_chr(x & 0xff)
        x >>= 8
    return b''.join(o)