Beispiel #1
0
def apply_msg(block, tx, msg, code):
    pblogger.log("MSG APPLY", tx=tx.hex_hash(), sender=msg.sender, to=msg.to,
                                  gas=msg.gas, value=msg.value, data=msg.data.encode('hex'))
    if pblogger.log_pre_state:
        pblogger.log('MSG PRE STATE', account=msg.to, state=block.account_to_dict(msg.to))
    # Transfer value, instaquit if not enough
    o = block.transfer_value(msg.sender, msg.to, msg.value)
    if not o:
        return 1, msg.gas, []
    snapshot = block.snapshot()
    compustate = Compustate(gas=msg.gas)
    t, ops = time.time(), 0
    if code in code_cache:
        processed_code = code_cache[code]
    else:
        processed_code = [opcodes.get(ord(c), ['INVALID', 0, 0, [], 0]) +
                          [ord(c)] for c in code]
        code_cache[code] = processed_code
    # Main loop
    while 1:
        o = apply_op(block, tx, msg, processed_code, compustate)
        ops += 1
        if o is not None:
            pblogger.log('MSG APPLIED', result=o, gas_remained=compustate.gas,
                        sender=msg.sender, to=msg.to, ops=ops,
                        time_per_op=(time.time() - t) / ops)
            if pblogger.log_post_state:
                    pblogger.log('MSG POST STATE', account=msg.to,
                        state=block.account_to_dict(msg.to))

            if o == OUT_OF_GAS:
                block.revert(snapshot)
                return 0, compustate.gas, []
            else:
                return 1, compustate.gas, o
Beispiel #2
0
def gas_estimate(code, depth=0):
    if isinstance(code.value, int):
        return 3
    elif isinstance(code.value, str) and (code.value.upper() in opcodes or code.value.upper() in pseudo_opcodes):
        decl = opcodes.get(code.value.upper(), pseudo_opcodes.get(code.value.upper(), None))
        o = sum([gas_estimate(c, depth + i) for i, c in enumerate(code.args[::-1])]) + decl[3]
        # Dynamic gas costs
        if code.value.upper() == 'CALL' and code.args[2].value != 0:
            o += 34000
        if code.value.upper() == 'SSTORE' and code.args[1].value != 0:
            o += 15000
        if code.value.upper() in ('SUICIDE', 'SELFDESTRUCT'):
            o += 25000
        if code.value.upper() == 'BREAK':
            o += opcodes['POP'][3] * depth
        return o
    elif isinstance(code.value, str) and code.value == 'if':
        if (len(code.args) == 2):
            return gas_estimate(code.args[0], depth + 1) + gas_estimate(code.args[1], depth + 1) + 30
        elif (len(code.args) == 3):
            return gas_estimate(code.args[0], depth + 1) + max(gas_estimate(code.args[1], depth + 1), gas_estimate(code.args[2], depth + 1)) + 30
        else:
            raise Exception("If statement must have 2 or 3 child elements")
    elif isinstance(code.value, str) and code.value == 'with':
        return gas_estimate(code.args[1], depth + 1) + gas_estimate(code.args[2], depth + 1) + 20
    elif isinstance(code.value, str) and code.value == 'repeat':
        return (gas_estimate(code.args[2], depth + 1) + 50) * code.args[0].value + 30
    elif isinstance(code.value, str) and code.value == 'seq':
        return sum([gas_estimate(c, depth + 1) for c in code.args])
    elif isinstance(code.value, str):
        return 3
    else:
        raise Exception("Gas estimate failed: "+repr(code))
 def execute(self):
     # some common stuff
     if not self.is_readable(self.cur_addr):
         raise MemReadLockedError((self.cur_addr, self.cur_addr))
     current_word = self.get_cur_word()
     c = current_word[5]
     f = current_word[4]
     op = opcodes.get(c, opcodes.get((c,f), None))
     self.jump_to = None
     before_cycles = self.cycles
     if self.op_hook is not None:
         self.op_hook(op.__name__, current_word)
     op(self)
     if self.jump_to is None:
         self.cur_addr += 1
     else:
         self.cur_addr = self.jump_to
     return self.cycles - before_cycles
Beispiel #4
0
def preprocess_vmcode(code):
    o = []
    jumps = {}
    # Round 1: Locate all JUMP, JUMPI, JUMPDEST, STOP, RETURN, INVALID locs
    opcodez = copy.deepcopy(
        [opcodes.get(ord(c), ['INVALID', 0, 0, 1]) + [ord(c)] for c in code])
    for i, o in enumerate(opcodez):
        if o[0] in filter1:
            jumps[i] = True

    chunks = {}
    chunks["code"] = [ord(x) for x in code]
    c = []
    h, reqh, gascost = 0, 0, 0
    i = 0
    laststart, lastjumpable = 0, 0
    while i < len(opcodez):
        o = opcodez[i]  # [op, ins, outs, gas, opcode, pos, push?]
        o.append(laststart + i)
        c.append(o)
        reqh = max(reqh, h + o[1])
        h += o[1] - o[2]
        gascost += o[3]
        if i in jumps:
            chunks[laststart] = {
                "reqh": reqh,
                "deltah": -h,
                "gascost": gascost,
                "opdata": c,
                "ops": list(enumerate([x[4] for x in c])),
                "start": laststart,
                "jumpable": lastjumpable,
                "end": i + 1
            }
            c = []
            laststart = i + 1
            lastjumpable = 1 if o[0] == 'JUMPDEST' else 0
            h, reqh, gascost = 0, 0, 0
        if 0x60 <= o[4] < 0x80:
            v = 0
            for j in range(i + 1, i + o[4] - 0x5e):
                v = (v << 8) + opcodez[j][4]
            o.append(v)
            i += o[4] - 0x5f
        i += 1
    chunks[laststart] = {
        "reqh": reqh,
        "deltah": -h,
        "gascost": gascost,
        "opdata": c,
        "ops": list(enumerate([x[4] for x in c])),
        "start": laststart,
        "jumpable": lastjumpable,
        "end": i + 1
    }
    return chunks
Beispiel #5
0
def apply_msg(block, tx, msg, code):
    pblogger.log("MSG APPLY",
                 tx=tx.hex_hash(),
                 sender=msg.sender,
                 to=msg.to,
                 gas=msg.gas,
                 value=msg.value,
                 data=msg.data.encode('hex'))
    if pblogger.log_pre_state:
        pblogger.log('MSG PRE STATE',
                     account=msg.to,
                     state=block.account_to_dict(msg.to))
    # Transfer value, instaquit if not enough
    o = block.transfer_value(msg.sender, msg.to, msg.value)
    if not o:
        return 1, msg.gas, []
    snapshot = block.snapshot()
    compustate = Compustate(gas=msg.gas)
    t, ops = time.time(), 0
    if code in code_cache:
        processed_code = code_cache[code]
    else:
        processed_code = [
            opcodes.get(ord(c), ['INVALID', 0, 0, [], 0]) + [ord(c)]
            for c in code
        ]
        code_cache[code] = processed_code
    # Main loop
    while 1:
        o = apply_op(block, tx, msg, processed_code, compustate)
        ops += 1
        if o is not None:
            pblogger.log('MSG APPLIED',
                         result=o,
                         gas_remained=compustate.gas,
                         sender=msg.sender,
                         to=msg.to,
                         ops=ops,
                         time_per_op=(time.time() - t) / ops)
            if pblogger.log_post_state:
                pblogger.log('MSG POST STATE',
                             account=msg.to,
                             state=block.account_to_dict(msg.to))

            if o == OUT_OF_GAS:
                block.revert(snapshot)
                return 0, compustate.gas, []
            else:
                return 1, compustate.gas, o
Beispiel #6
0
def get_op_data(code, index):
    opcode = ord(code[index]) if index < len(code) else 0
    return opcodes.get(opcode, ['INVALID', 0, 0, [], 0])
Beispiel #7
0
def get_op_data(code, index):
    opcode = ord(code[index]) if index < len(code) else 0
    return opcodes.get(opcode, ['INVALID', 0, 0, [], 0])
Beispiel #8
0
def get_op_data(code, index):
    return opcodes.get(get_opcode(code, index), ['INVALID', 0, 0, []])
Beispiel #9
0
def get_op_data(code, index):
    return opcodes.get(get_opcode(code, index), ['INVALID', 0, 0, []])
Beispiel #10
0
 def __init__(self, value, args=[], typ=None, annotation=None):
     self.value = value
     self.args = args
     self.typ = typ
     self.annotation = annotation
     # Determine this node's valency (1 if it pushes a value on the stack,
     # 0 otherwise) and checks to make sure the number and valencies of
     # children are correct
     # Numbers
     if isinstance(self.value, int):
         self.valency = 1
     elif isinstance(self.value, str):
         # Opcodes and pseudo-opcodes (eg. clamp)
         if self.value.upper() in opcodes or self.value.upper(
         ) in pseudo_opcodes:
             record = opcodes.get(
                 self.value.upper(),
                 pseudo_opcodes.get(self.value.upper(), None))
             self.valency = record[2]
             if len(self.args) != record[1]:
                 raise Exception("Number of arguments mismatched: %r %r" %
                                 (self.value, self.args))
             for arg in self.args:
                 if arg.valency == 0:
                     raise Exception(
                         "Can't have a zerovalent argument to an opcode or a pseudo-opcode! %r"
                         % arg)
         # If statements
         elif self.value == 'if':
             if len(self.args) == 3:
                 if self.args[1].valency != self.args[2].valency:
                     raise Exception(
                         "Valency mismatch between then and else clause: %r %r"
                         % (self.args[1], self.args[2]))
             if len(self.args) == 2 and self.args[1].valency:
                 raise Exception(
                     "2-clause if statement must have a zerovalent body: %r"
                     % self.args[1])
             if not self.args[0].valency:
                 raise Exception(
                     "Can't have a zerovalent argument as a test to an if statement! %r"
                     % self.args[0])
             if len(self.args) not in (2, 3):
                 raise Exception("If can only have 2 or 3 arguments")
             self.valency = self.args[1].valency
         # With statements: with <var> <initial> <statement>
         elif self.value == 'with':
             if len(self.args) != 3:
                 raise Exception("With statement must have 3 arguments")
             if len(self.args[0].args) or not isinstance(
                     self.args[0].value, str):
                 raise Exception(
                     "First argument to with statement must be a variable")
             if not self.args[1].valency:
                 raise Exception(
                     "Second argument to with statement (initial value) cannot be zerovalent: %r"
                     % self.args[1])
             self.valency = self.args[2].valency
         # Repeat statements: repeat <index_memloc> <startval> <rounds> <body>
         elif self.value == 'repeat':
             if len(self.args[2].args) or not isinstance(
                     self.args[2].value, int) or self.args[2].value <= 0:
                 raise Exception(
                     "Number of times repeated must be a constant nonzero positive integer"
                 )
             if not self.args[0].valency:
                 raise Exception(
                     "First argument to repeat (memory location) cannot be zerovalent: %r"
                     % self.args[0])
             if not self.args[1].valency:
                 raise Exception(
                     "Second argument to repeat (start value) cannot be zerovalent: %r"
                     % self.args[1])
             if self.args[3].valency:
                 raise Exception(
                     "Third argument to repeat (clause to be repeated) must be zerovalent: %r"
                     % self.args[3])
             self.valency = 0
         # Seq statements: seq <statement> <statement> ...
         elif self.value == 'seq':
             self.valency = self.args[-1].valency if self.args else 0
         # Variables
         else:
             self.valency = 1
     else:
         raise Exception("Invalid value for LLL AST node: %r" % self.value)
     assert isinstance(self.args, list)