def add_block(self, block): blockhash = block.hash() if blockhash == GENESIS_H: parent_score = 0 else: try: parent = rlp.decode(self.blockchain.get(block.prevhash)) except: raise Exception("Parent of block not found") parent_score = utils.big_endian_to_int(parent[1]) total_score = utils.int_to_big_endian(block.difficulty + parent_score) self.blockchain.put( blockhash, rlp.encode([block.serialize(), total_score])) try: head = self.blockchain.get('head') head_data = rlp.decode(self.blockchain.get(head)) head_score = utils.big_endian_to_int(head_data[1]) except: head_score = 0 if total_score > head_score: self.head = blockhash self.blockchain.put('head', blockhash) return True return False
def __decode(s, pos=0): assert pos < len(s), "read beyond end of string in __decode" fchar = ord(s[pos]) if fchar < 128: return (s[pos], pos + 1) elif fchar < 184: b = fchar - 128 return (s[pos + 1:pos + 1 + b], pos + 1 + b) elif fchar < 192: b = fchar - 183 b2 = big_endian_to_int(s[pos + 1:pos + 1 + b]) return (s[pos + 1 + b:pos + 1 + b + b2], pos + 1 + b + b2) elif fchar < 248: o = [] pos += 1 pos_end = pos + fchar - 192 while pos < pos_end: obj, pos = __decode(s, pos) o.append(obj) assert pos == pos_end, "read beyond list boundary in __decode" return (o, pos) else: b = fchar - 247 b2 = big_endian_to_int(s[pos + 1:pos + 1 + b]) o = [] pos += 1 + b pos_end = pos + b2 while pos < pos_end: obj, pos = __decode(s, pos) o.append(obj) assert pos == pos_end, "read beyond list boundary in __decode" return (o, pos)
def decode_single(typ, data): base, sub, _ = typ if base == 'address': return encode_hex(data[12:]) elif base == 'hash': return data[32 - int(sub):] elif base == 'string' or base == 'bytes': if len(sub): return data[:int(sub)] else: l = big_endian_to_int(data[0:32]) return data[32:][:l] elif base == 'uint': return big_endian_to_int(data) elif base == 'int': o = big_endian_to_int(data) return (o - 2**int(sub)) if o >= 2**(int(sub) - 1) else o elif base == 'ureal': high, low = [int(x) for x in sub.split('x')] return big_endian_to_int(data) * 1.0 // 2**low elif base == 'real': high, low = [int(x) for x in sub.split('x')] o = big_endian_to_int(data) i = (o - 2**(high + low)) if o >= 2**(high + low - 1) else o return (i * 1.0 // 2**low) elif base == 'bool': return bool(int(encode_hex(data), 16))
def decode_single(typ, data): base, sub, _ = typ if base == 'address': return encode_hex(data[12:]) elif base == 'hash': return data[32 - int(sub):] elif base == 'string' or base == 'bytes': if len(sub): return data[:int(sub)] else: l = big_endian_to_int(data[0:32]) return data[32:][:l] elif base == 'uint': return big_endian_to_int(data) elif base == 'int': o = big_endian_to_int(data) return (o - 2 ** int(sub)) if o >= 2 ** (int(sub) - 1) else o elif base == 'ureal': high, low = [int(x) for x in sub.split('x')] return big_endian_to_int(data) * 1.0 // 2 ** low elif base == 'real': high, low = [int(x) for x in sub.split('x')] o = big_endian_to_int(data) i = (o - 2 ** (high + low)) if o >= 2 ** (high + low - 1) else o return (i * 1.0 // 2 ** low) elif base == 'bool': return bool(int(encode_hex(data), 16))
def __init__(self, pubkey): assert len(pubkey) == 64 and isinstance(pubkey, str) self.pubkey = pubkey if k_id_size == 512: self.id = big_endian_to_int(pubkey) else: assert k_id_size == 256 self.id = big_endian_to_int(sha3(pubkey))
def get_tx_position(self, tx): if isinstance(tx,str): tx = tx.decode("HEX") elif not isinstance(tx, bytes): tx = tx.hash if b'txindex:' + tx in self.db: data = rlp.decode(self.db.get(b'txindex:' + tx)) return big_endian_to_int(data[0]), big_endian_to_int(data[1]) else: return None
def mine(self, steps=1000): """ It is formally defined as PoW: PoW(H, n) = BE(SHA3(SHA3(RLP(Hn)) o n)) where: RLP(Hn) is the RLP encoding of the block header H, not including the final nonce component; SHA3 is the SHA3 hash function accepting an arbitrary length series of bytes and evaluating to a series of 32 bytes (i.e. 256-bit); n is the nonce, a series of 32 bytes; o is the series concatenation operator; BE(X) evaluates to the value equal to X when interpreted as a big-endian-encoded integer. """ nonce_bin_prefix = '\x00' * (32 - len(struct.pack('>q', 0))) target = 2**256 / self.block.difficulty rlp_Hn = self.block.serialize_header_without_nonce() for nonce in range(self.nonce, self.nonce + steps): nonce_bin = nonce_bin_prefix + struct.pack('>q', nonce) # BE(SHA3(SHA3(RLP(Hn)) o n)) h = utils.sha3(utils.sha3(rlp_Hn) + nonce_bin) l256 = utils.big_endian_to_int(h) if l256 < target: self.block.nonce = nonce_bin assert self.block.check_proof_of_work(self.block.nonce) is True assert self.block.get_parent() logger.debug('Nonce found %d %r', nonce, self.block) return self.block self.nonce = nonce return False
def account_to_dict(self, address, with_storage_root=False): if with_storage_root: assert len(self.journal) == 0 med_dict = {} for i, val in enumerate(self.get_acct(address)): name, typ, default = acct_structure[i] key = acct_structure[i][0] if name == 'storage': strie = trie.Trie(utils.get_db_path(), val) if with_storage_root: med_dict['storage_root'] = strie.get_root_hash().encode('hex') else: med_dict[key] = self.caches[key].get(address, utils.printers[typ](val)) med_dict['storage'] = {} d = strie.to_dict() for k in d.keys() + self.caches['all'].keys(): v = d.get(k, None) subcache = self.caches.get('storage:'+address, {}) v2 = subcache.get(utils.big_endian_to_int(k), None) hexkey = '0x'+k.encode('hex') if v2 is not None: if v2 != 0: med_dict['storage'][hexkey] = '0x'+utils.int_to_big_endian(v2).encode('hex') elif v is not None: med_dict['storage'][hexkey] = '0x'+rlp.decode(v).encode('hex') return med_dict
def account_to_dict(self, address, with_storage_root=False, with_storage=True, for_vmtest=False): if with_storage_root: assert len(self.journal) == 0 med_dict = {} for i, val in enumerate(self.get_acct(address)): name, typ, default = acct_structure[i] key = acct_structure[i][0] if name == 'storage': strie = trie.Trie(self.db, val) if with_storage_root: med_dict['storage_root'] = strie.get_root_hash().encode('hex') else: med_dict[key] = utils.printers[typ](self.caches[key].get(address, val)) if with_storage: med_dict['storage'] = {} d = strie.to_dict() subcache = self.caches.get('storage:' + address, {}) subkeys = [utils.zpad(utils.coerce_to_bytes(kk), 32) for kk in subcache.keys()] for k in d.keys() + subkeys: v = d.get(k, None) v2 = subcache.get(utils.big_endian_to_int(k), None) hexkey = '0x' + utils.zunpad(k).encode('hex') if v2 is not None: if v2 != 0: med_dict['storage'][hexkey] = \ '0x' + utils.int_to_big_endian(v2).encode('hex') elif v is not None: med_dict['storage'][hexkey] = '0x' + rlp.decode(v).encode('hex') return med_dict
def check_header_pow(header): rlp_Hn = rlp.encode(header[:-1]) nonce = header[-1] assert len(nonce) == 32 diff = utils.decoders['int'](header[block_structure_rev['difficulty'][0]]) h = utils.sha3(utils.sha3(rlp_Hn) + nonce) return utils.big_endian_to_int(h) < 2 ** 256 / diff
def check_proof_of_work(self, nonce): assert len(nonce) == 32 rlp_Hn = self.serialize_header_without_nonce() # BE(SHA3(SHA3(RLP(Hn)) o n)) h = utils.sha3(utils.sha3(rlp_Hn) + nonce) l256 = utils.big_endian_to_int(h) return l256 < 2 ** 256 / self.difficulty
def decode_datalist(arr): if isinstance(arr, list): arr = ''.join(map(chr, arr)) o = [] for i in range(0, len(arr), 32): o.append(utils.big_endian_to_int(arr[i:i + 32])) return o
def mine(self, steps=1000): """ It is formally defined as PoW: PoW(H, n) = BE(SHA3(SHA3(RLP(Hn)) o n)) where: RLP(Hn) is the RLP encoding of the block header H, not including the final nonce component; SHA3 is the SHA3 hash function accepting an arbitrary length series of bytes and evaluating to a series of 32 bytes (i.e. 256-bit); n is the nonce, a series of 32 bytes; o is the series concatenation operator; BE(X) evaluates to the value equal to X when interpreted as a big-endian-encoded integer. """ nonce_bin_prefix = '\x00' * (32 - len(struct.pack('>q', 0))) target = 2 ** 256 / self.block.difficulty rlp_Hn = self.block.serialize_header_without_nonce() for nonce in range(self.nonce, self.nonce + steps): nonce_bin = nonce_bin_prefix + struct.pack('>q', nonce) # BE(SHA3(SHA3(RLP(Hn)) o n)) h = utils.sha3(utils.sha3(rlp_Hn) + nonce_bin) l256 = utils.big_endian_to_int(h) if l256 < target: self.block.nonce = nonce_bin assert self.block.check_proof_of_work(self.block.nonce) is True assert self.block.get_parent() logger.debug( 'Nonce found %d %r', nonce, self.block) return self.block self.nonce = nonce return False
def check_header_pow(header): assert len(header[-1]) == 32 rlp_Hn = rlp.encode(header[:-1]) nonce = header[-1] diff = utils.decoders['int'](header[block_structure_rev['difficulty'][0]]) h = utils.sha3(utils.sha3(rlp_Hn) + nonce) return utils.big_endian_to_int(h) < 2 ** 256 / diff
def check_proof_of_work(self, nonce): assert len(nonce) == 32 rlp_Hn = self.serialize_header_without_nonce() # BE(SHA3(SHA3(RLP(Hn)) o n)) h = utils.sha3(utils.sha3(rlp_Hn) + nonce) l256 = utils.big_endian_to_int(h) return l256 < 2**256 / self.difficulty
def account_to_dict(self, address, with_storage_root=False): if with_storage_root: assert len(self.journal) == 0 med_dict = {} for i, val in enumerate(self.get_acct(address)): name, typ, default = acct_structure[i] key = acct_structure[i][0] if name == 'storage': strie = trie.Trie(utils.get_db_path(), val) if with_storage_root: med_dict['storage_root'] = strie.get_root_hash().encode( 'hex') else: med_dict[key] = self.caches[key].get(address, utils.printers[typ](val)) med_dict['storage'] = {} d = strie.to_dict() for k in d.keys() + self.caches['all'].keys(): v = d.get(k, None) subcache = self.caches.get('storage:' + address, {}) v2 = subcache.get(utils.big_endian_to_int(k), None) hexkey = '0x' + k.encode('hex') if v2 is not None: if v2 != 0: med_dict['storage'][ hexkey] = '0x' + utils.int_to_big_endian(v2).encode( 'hex') elif v is not None: med_dict['storage'][hexkey] = '0x' + rlp.decode(v).encode( 'hex') return med_dict
def dec(typ, arg): base, sub, arrlist = typ sz = get_size(typ) # Dynamic-sized strings are encoded as <len(str)> + <str> if base in ('string', 'bytes') and not sub: L = big_endian_to_int(arg[:32]) assert len( arg[32:]) == ceil32(L), "Wrong data size for string/bytes object" return arg[32:][:L] # Dynamic-sized arrays elif sz is None: L = big_endian_to_int(arg[:32]) subtyp = base, sub, arrlist[:-1] subsize = get_size(subtyp) # If children are dynamic, use the head/tail mechanism. Fortunately, # here the code is simpler since we do not have to worry about # mixed dynamic and static children, as we do in the top-level multi-arg # case if subsize is None: assert len(arg) >= 32 + 32 * L, "Not enough data for head" start_positions = [ big_endian_to_int(arg[32 + 32 * i:64 + 32 * i]) for i in range(L) ] + [len(arg)] outs = [ arg[start_positions[i]:start_positions[i + 1]] for i in range(L) ] return [dec(subtyp, out) for out in outs] # If children are static, then grab the data slice for each one and # sequentially decode them manually else: return [ dec(subtyp, arg[32 + subsize * i:32 + subsize * (i + 1)]) for i in range(L) ] # Static-sized arrays: decode piece-by-piece elif len(arrlist): L = arrlist[-1][0] subtyp = base, sub, arrlist[:-1] subsize = get_size(subtyp) return [ dec(subtyp, arg[subsize * i:subsize * (i + 1)]) for i in range(L) ] else: return decode_single(typ, arg)
def get_storage_data(self, address, index): CACHE_KEY = 'storage:'+address if CACHE_KEY in self.caches: if index in self.caches[CACHE_KEY]: return self.caches[CACHE_KEY][index] key = utils.zpad(utils.coerce_to_bytes(index), 32) val = rlp.decode(self.get_storage(address).get(key)) return utils.big_endian_to_int(val) if val else 0
def get_storage_data(self, address, index): if address in self.caches['storage']: if index in self.caches['storage'][address]: return self.caches['storage'][address][index] t = self.get_storage(address) key = utils.zpad(utils.coerce_to_bytes(index), 32) val = rlp.decode(t.get(key)) return utils.big_endian_to_int(val) if val else 0
def next(data, pos): fchar = ord(data[pos]) if fchar < 128: return pos + 1 elif (fchar % 64) < 56: return pos + 1 + (fchar % 64) else: b = (fchar % 64) - 55 b2 = big_endian_to_int(data[pos + 1:pos + 1 + b]) return pos + 1 + b + b2
def get_storage_data(self, address, index): if 'storage:'+address in self.caches: if index in self.caches['storage:'+address]: return self.caches['storage:'+address][index] t = self.get_storage(address) t.proof_mode = self.proof_mode t.proof_nodes = self.proof_nodes key = utils.zpad(utils.coerce_to_bytes(index), 32) val = rlp.decode(t.get(key)) if self.proof_mode == RECORDING: self.proof_nodes.extend(t.proof_nodes) return utils.big_endian_to_int(val) if val else 0
def get_storage_data(self, address, index): if 'storage:' + address in self.caches: if index in self.caches['storage:' + address]: return self.caches['storage:' + address][index] t = self.get_storage(address) t.proof_mode = self.proof_mode t.proof_nodes = self.proof_nodes key = utils.zpad(utils.coerce_to_bytes(index), 32) val = rlp.decode(t.get(key)) if self.proof_mode == RECORDING: self.proof_nodes.extend(t.proof_nodes) return utils.big_endian_to_int(val) if val else 0
def dec(typ, arg): base, sub, arrlist = typ sz = get_size(typ) # Dynamic-sized strings are encoded as <len(str)> + <str> if base in ('string', 'bytes') and not sub: L = big_endian_to_int(arg[:32]) assert len(arg[32:]) == ceil32(L), "Wrong data size for string/bytes object" return arg[32:][:L] # Dynamic-sized arrays elif sz is None: L = big_endian_to_int(arg[:32]) subtyp = base, sub, arrlist[:-1] subsize = get_size(subtyp) # If children are dynamic, use the head/tail mechanism. Fortunately, # here the code is simpler since we do not have to worry about # mixed dynamic and static children, as we do in the top-level multi-arg # case if subsize is None: assert len(arg) >= 32 + 32 * L, "Not enough data for head" start_positions = [big_endian_to_int(arg[32 + 32 * i: 64 + 32 * i]) for i in range(L)] + [len(arg)] outs = [arg[start_positions[i]: start_positions[i + 1]] for i in range(L)] return [dec(subtyp, out) for out in outs] # If children are static, then grab the data slice for each one and # sequentially decode them manually else: return [dec(subtyp, arg[32 + subsize * i: 32 + subsize * (i + 1)]) for i in range(L)] # Static-sized arrays: decode piece-by-piece elif len(arrlist): L = arrlist[-1][0] subtyp = base, sub, arrlist[:-1] subsize = get_size(subtyp) return [dec(subtyp, arg[subsize * i:subsize * (i + 1)]) for i in range(L)] else: return decode_single(typ, arg)
def event_id(name, encode_types): """ Return the event id. Defined as: `keccak(EVENT_NAME+"("+EVENT_ARGS.map(canonical_type_of).join(",")+")")` Where `canonical_type_of` is a function that simply returns the canonical type of a given argument, e.g. for uint indexed foo, it would return uint256). Note the lack of spaces. """ event_types = [_canonical_name(type_) for type_ in encode_types] event_signature = '{event_name}({canonical_types})'.format( event_name=name, canonical_types=','.join(event_types), ) return big_endian_to_int(utils.sha3(event_signature))
def method_id(name, encode_types): """ Return the unique method id. The signature is defined as the canonical expression of the basic prototype, i.e. the function name with the parenthesised list of parameter types. Parameter types are split by a single comma - no spaces are used. The method id is defined as the first four bytes (left, high-order in big-endian) of the Keccak (SHA-3) hash of the signature of the function. """ function_types = [_canonical_name(type_) for type_ in encode_types] function_signature = '{function_name}({canonical_types})'.format( function_name=name, canonical_types=','.join(function_types), ) function_keccak = utils.sha3(function_signature) first_bytes = function_keccak[:4] return big_endian_to_int(first_bytes)
def decode_abi(types, data): # Process types proctypes = [process_type(typ) for typ in types] # Get sizes of everything sizes = [get_size(typ) for typ in proctypes] # Initialize array of outputs outs = [None] * len(types) # Initialize array of start positions start_positions = [None] * len(types) + [len(data)] # If a type is static, grab the data directly, otherwise record # its start position pos = 0 for i, typ in enumerate(types): if sizes[i] is None: start_positions[i] = big_endian_to_int(data[pos:pos + 32]) j = i - 1 while j >= 0 and start_positions[j] is None: start_positions[j] = start_positions[i] j -= 1 pos += 32 else: outs[i] = data[pos:pos + sizes[i]] pos += sizes[i] # We add a start position equal to the length of the entire data # for convenience. j = len(types) - 1 while j >= 0 and start_positions[j] is None: start_positions[j] = start_positions[len(types)] j -= 1 assert pos <= len(data), "Not enough data for head" # Grab the data for tail arguments using the start positions # calculated above for i, typ in enumerate(types): if sizes[i] is None: offset = start_positions[i] next_offset = start_positions[i + 1] outs[i] = data[offset:next_offset] # Recursively decode them all return [dec(proctypes[i], outs[i]) for i in range(len(outs))]
def decint(n, signed=False): if isinstance(n, str): n = utils.to_string(n) if is_numeric(n): min_, max_ = (-TT255, TT255 - 1) if signed else (0, TT256 - 1) if n > max_ or n < min_: raise EncodingError("Number out of range: %r" % n) return n elif is_string(n): if len(n) == 40: n = decode_hex(n) if len(n) > 32: raise EncodingError("String too long: %r" % n) i = big_endian_to_int(n) return (i - TT256) if signed and i >= TT255 else i elif n is True: return 1 elif n is False or n is None: return 0 else: raise EncodingError("Cannot encode integer: %r" % n)
def account_to_dict(self, address, with_storage_root=False): if with_storage_root: assert len(self.journal) == 0 med_dict = {} for i, val in enumerate(self.get_acct(address)): name, typ, default = acct_structure[i] key = acct_structure[i][0] if name == "storage": strie = trie.Trie(utils.get_db_path(), val) if with_storage_root: med_dict["storage_root"] = strie.get_root_hash().encode("hex") else: med_dict[key] = self.caches[key].get(address, utils.printers[typ](val)) med_dict["storage"] = {} for k, v in strie.to_dict().iteritems(): subcache = self.caches.get("storage:" + address, {}) v2 = subcache.get(utils.big_endian_to_int(k), None) hexkey = "0x" + k.encode("hex") if v2 is not None: med_dict["storage"][hexkey] = "0x" + utils.int_to_big_endian(v2).encode("hex") else: med_dict["storage"][hexkey] = "0x" + v.encode("hex") return med_dict
def event_id(name, encode_types): """ Return the event id. Defined as: `keccak(EVENT_NAME+"("+EVENT_ARGS.map(canonical_type_of).join(",")+")")` Where `canonical_type_of` is a function that simply returns the canonical type of a given argument, e.g. for uint indexed foo, it would return uint256). Note the lack of spaces. """ event_types = [ _canonical_name(type_) for type_ in encode_types ] event_signature = '{event_name}({canonical_types})'.format( event_name=name, canonical_types=','.join(event_types), ) return big_endian_to_int(utils.sha3(event_signature))
def decint(n, signed=False): if isinstance(n, str): n = utils.to_string(n) if is_numeric(n): min, max = (-TT255, TT255 - 1) if signed else (0, TT256 - 1) if n > max or n < min: raise EncodingError("Number out of range: %r" % n) return n elif is_string(n): if len(n) == 40: n = decode_hex(n) if len(n) > 32: raise EncodingError("String too long: %r" % n) i = big_endian_to_int(n) return (i - TT256) if signed and i >= TT255 else i elif n is True: return 1 elif n is False or n is None: return 0 else: raise EncodingError("Cannot encode integer: %r" % n)
def method_id(name, encode_types): """ Return the unique method id. The signature is defined as the canonical expression of the basic prototype, i.e. the function name with the parenthesised list of parameter types. Parameter types are split by a single comma - no spaces are used. The method id is defined as the first four bytes (left, high-order in big-endian) of the Keccak (SHA-3) hash of the signature of the function. """ function_types = [ _canonical_name(type_) for type_ in encode_types ] function_signature = '{function_name}({canonical_types})'.format( function_name=name, canonical_types=','.join(function_types), ) function_keccak = utils.sha3(function_signature) first_bytes = function_keccak[:4] return big_endian_to_int(first_bytes)
def apply_op(block, tx, msg, code, compustate): op, in_args, out_args = get_op_data(code, compustate.pc) # empty stack error if in_args > len(compustate.stack): return [] # out of gas error fee = calcfee(block, tx, msg, compustate, op) if fee > compustate.gas: logger.debug("Out of gas %s need %s", compustate.gas, fee) logger.debug('%s %s', op, list(reversed(compustate.stack))) return OUT_OF_GAS stackargs = [] for i in range(in_args): stackargs.append(compustate.stack.pop()) if op[:4] == 'PUSH': ind = compustate.pc + 1 v = utils.big_endian_to_int(code[ind: ind + int(op[4:])]) logger.debug('%s %x %s', compustate.pc, op, v) # print '%s %s %s' % (compustate.pc, op, v) else: logger.debug('%s %s %s', compustate.pc, op, stackargs) # print '%s %s %s' % (compustate.pc, op, stackargs) # Apply operation oldgas = compustate.gas oldpc = compustate.pc compustate.gas -= fee compustate.pc += 1 stk = compustate.stack mem = compustate.memory if op == 'STOP': return [] elif op == 'ADD': stk.append((stackargs[0] + stackargs[1]) % 2 ** 256) elif op == 'SUB': stk.append((stackargs[0] - stackargs[1]) % 2 ** 256) elif op == 'MUL': stk.append((stackargs[0] * stackargs[1]) % 2 ** 256) elif op == 'DIV': if stackargs[1] == 0: return [] stk.append(stackargs[0] / stackargs[1]) elif op == 'MOD': if stackargs[1] == 0: return [] stk.append(stackargs[0] % stackargs[1]) elif op == 'SDIV': if stackargs[1] == 0: return [] if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append((stackargs[0] / stackargs[1]) % 2 ** 256) elif op == 'SMOD': if stackargs[1] == 0: return [] if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append((stackargs[0] % stackargs[1]) % 2 ** 256) elif op == 'EXP': stk.append(pow(stackargs[0], stackargs[1], 2 ** 256)) elif op == 'NEG': stk.append(2 ** 256 - stackargs[0]) elif op == 'LT': stk.append(1 if stackargs[0] < stackargs[1] else 0) elif op == 'GT': stk.append(1 if stackargs[0] > stackargs[1] else 0) elif op == 'SLT': if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append(1 if stackargs[0] < stackargs[1] else 0) elif op == 'SGT': if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append(1 if stackargs[0] > stackargs[1] else 0) elif op == 'EQ': stk.append(1 if stackargs[0] == stackargs[1] else 0) elif op == 'NOT': stk.append(0 if stackargs[0] else 1) elif op == 'AND': stk.append(stackargs[0] & stackargs[1]) elif op == 'OR': stk.append(stackargs[0] | stackargs[1]) elif op == 'XOR': stk.append(stackargs[0] ^ stackargs[1]) elif op == 'BYTE': if stackargs[0] >= 32: stk.append(0) else: stk.append((stackargs[1] / 256 ** stackargs[0]) % 256) elif op == 'SHA3': if len(mem) < ceil32(stackargs[0] + stackargs[1]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[1]) - len(mem))) data = ''.join(map(chr, mem[stackargs[0]:stackargs[0] + stackargs[1]])) stk.append(utils.big_endian_to_int(utils.sha3(data))) elif op == 'ADDRESS': stk.append(msg.to) elif op == 'BALANCE': stk.append(block.get_balance(msg.to)) elif op == 'ORIGIN': stk.append(tx.sender) elif op == 'CALLER': stk.append(utils.coerce_to_int(msg.sender)) elif op == 'CALLVALUE': stk.append(msg.value) elif op == 'CALLDATALOAD': if stackargs[0] >= len(msg.data): stk.append(0) else: dat = msg.data[stackargs[0]:stackargs[0] + 32] stk.append(utils.big_endian_to_int(dat + '\x00' * (32 - len(dat)))) elif op == 'CALLDATASIZE': stk.append(len(msg.data)) elif op == 'CALLDATACOPY': if len(mem) < ceil32(stackargs[1] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[1] + stackargs[2]) - len(mem))) for i in range(stackargs[2]): if stackargs[0] + i < len(msg.data): mem[stackargs[1] + i] = ord(msg.data[stackargs[0] + i]) else: mem[stackargs[1] + i] = 0 elif op == 'GASPRICE': stk.append(tx.gasprice) elif op == 'CODECOPY': if len(mem) < ceil32(stackargs[1] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[1] + stackargs[2]) - len(mem))) for i in range(stackargs[2]): if stackargs[0] + i < len(code): mem[stackargs[1] + i] = ord(code[stackargs[0] + i]) else: mem[stackargs[1] + i] = 0 elif op == 'PREVHASH': stk.append(utils.big_endian_to_int(block.prevhash)) elif op == 'COINBASE': stk.append(utils.big_endian_to_int(block.coinbase.decode('hex'))) elif op == 'TIMESTAMP': stk.append(block.timestamp) elif op == 'NUMBER': stk.append(block.number) elif op == 'DIFFICULTY': stk.append(block.difficulty) elif op == 'GASLIMIT': stk.append(block.gaslimit) elif op == 'POP': pass elif op == 'DUP': stk.append(stackargs[0]) stk.append(stackargs[0]) elif op == 'SWAP': stk.append(stackargs[0]) stk.append(stackargs[1]) elif op == 'MLOAD': if len(mem) < ceil32(stackargs[0] + 32): mem.extend([0] * (ceil32(stackargs[0] + 32) - len(mem))) data = ''.join(map(chr, mem[stackargs[0]:stackargs[0] + 32])) stk.append(utils.big_endian_to_int(data)) elif op == 'MSTORE': if len(mem) < ceil32(stackargs[0] + 32): mem.extend([0] * (ceil32(stackargs[0] + 32) - len(mem))) v = stackargs[1] for i in range(31, -1, -1): mem[stackargs[0] + i] = v % 256 v /= 256 elif op == 'MSTORE8': if len(mem) < ceil32(stackargs[0] + 1): mem.extend([0] * (ceil32(stackargs[0] + 1) - len(mem))) mem[stackargs[0]] = stackargs[1] % 256 elif op == 'SLOAD': stk.append(block.get_storage_data(msg.to, stackargs[0])) elif op == 'SSTORE': block.set_storage_data(msg.to, stackargs[0], stackargs[1]) elif op == 'JUMP': compustate.pc = stackargs[0] elif op == 'JUMPI': if stackargs[1]: compustate.pc = stackargs[0] elif op == 'PC': stk.append(compustate.pc) elif op == 'MSIZE': stk.append(len(mem)) elif op == 'GAS': stk.append(oldgas) elif op[:4] == 'PUSH': pushnum = int(op[4:]) compustate.pc = oldpc + 1 + pushnum dat = code[oldpc + 1: oldpc + 1 + pushnum] stk.append(utils.big_endian_to_int(dat)) elif op == 'CREATE': if len(mem) < ceil32(stackargs[1] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[1] + stackargs[2]) - len(mem))) value = stackargs[0] data = ''.join(map(chr, mem[stackargs[1]:stackargs[1] + stackargs[2]])) logger.debug("Sub-contract: %s %s %s ", msg.to, value, data) addr, gas, code = create_contract( block, tx, Message(msg.to, '', value, compustate.gas, data)) logger.debug("Output of contract creation: %s %s ", addr, code) if addr: stk.append(utils.coerce_to_int(addr)) compustate.gas = gas else: stk.append(0) compustate.gas = 0 elif op == 'CALL': if len(mem) < ceil32(stackargs[3] + stackargs[4]): mem.extend([0] * (ceil32(stackargs[3] + stackargs[4]) - len(mem))) if len(mem) < ceil32(stackargs[5] + stackargs[6]): mem.extend([0] * (ceil32(stackargs[5] + stackargs[6]) - len(mem))) gas = stackargs[0] to = utils.encode_int(stackargs[1]) to = (('\x00' * (32 - len(to))) + to)[12:] value = stackargs[2] data = ''.join(map(chr, mem[stackargs[3]:stackargs[3] + stackargs[4]])) logger.debug( "Sub-call: %s %s %s %s %s ", utils.coerce_addr_to_hex(msg.to), utils.coerce_addr_to_hex(to), value, gas, data) result, gas, data = apply_msg( block, tx, Message(msg.to, to, value, gas, data)) logger.debug( "Output of sub-call: %s %s length %s expected %s", result, data, len(data), stackargs[6]) for i in range(stackargs[6]): mem[stackargs[5] + i] = 0 if result == 0: stk.append(0) else: stk.append(1) compustate.gas += gas for i in range(len(data)): mem[stackargs[5] + i] = data[i] elif op == 'RETURN': if len(mem) < ceil32(stackargs[0] + stackargs[1]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[1]) - len(mem))) return mem[stackargs[0]:stackargs[0] + stackargs[1]] elif op == 'SUICIDE': to = utils.encode_int(stackargs[0]) to = (('\x00' * (32 - len(to))) + to)[12:] block.transfer_value(msg.to, to, block.get_balance(msg.to)) compustate.suicides.append(msg.to) return []
def apply_op(block, tx, msg, processed_code, compustate): if compustate.pc >= len(processed_code): return [] op, in_args, out_args, mem_grabs, fee, opcode = processed_code[compustate.pc] # empty stack error if in_args > len(compustate.stack): pblogger.log("INSUFFICIENT STACK ERROR", op=op, needed=in_args, available=len(compustate.stack)) return [] # out of gas error if fee > compustate.gas: return out_of_gas_exception("base_gas", fee, compustate, op) if pblogger.log_apply_op: if pblogger.log_stack: pblogger.log("STK", stk=list(reversed(compustate.stack))) if pblogger.log_memory: for i in range(0, len(compustate.memory), 16): memblk = compustate.memory[i : i + 16] memline = " ".join([chr(x).encode("hex") for x in memblk]) pblogger.log("MEM", mem=memline) if pblogger.log_storage: pblogger.log("STORAGE", storage=block.account_to_dict(msg.to)["storage"]) if pblogger.log_op: log_args = dict( pc=compustate.pc, op=op, stackargs=compustate.stack[-1 : -in_args - 1 : -1], gas=compustate.gas ) if op[:4] == "PUSH": ind = compustate.pc + 1 log_args["value"] = utils.bytearray_to_int([x[-1] for x in processed_code[ind : ind + int(op[4:])]]) elif op == "CALLDATACOPY": log_args["data"] = msg.data.encode("hex") pblogger.log("OP", **log_args) # Apply operation compustate.gas -= fee compustate.pc += 1 stk = compustate.stack mem = compustate.memory if op == "STOP" or op == "INVALID": return [] elif op == "ADD": stk.append((stk.pop() + stk.pop()) % TT256) elif op == "SUB": stk.append((stk.pop() - stk.pop()) % TT256) elif op == "MUL": stk.append((stk.pop() * stk.pop()) % TT256) 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 = to_signed(stk.pop()), to_signed(stk.pop()) stk.append(0 if s1 == 0 else (s0 / s1) % TT256) elif op == "SMOD": s0, s1 = to_signed(stk.pop()), to_signed(stk.pop()) stk.append(0 if s1 == 0 else (s0 % s1) % TT256) elif op == "EXP": stk.append(pow(stk.pop(), stk.pop(), TT256)) elif op == "NEG": stk.append(-stk.pop() % TT256) elif 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 = to_signed(stk.pop()), to_signed(stk.pop()) stk.append(1 if s0 < s1 else 0) elif op == "SGT": s0, s1 = to_signed(stk.pop()), 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 == "NOT": 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 == "BYTE": s0, s1 = stk.pop(), stk.pop() if s0 >= 32: stk.append(0) else: stk.append((s1 / 256 ** (31 - s0)) % 256) 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 == "SHA3": s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0 + s1): return OUT_OF_GAS data = "".join(map(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": stk.append(block.get_balance(utils.coerce_addr_to_hex(stk.pop()))) elif op == "ORIGIN": stk.append(utils.coerce_to_int(tx.sender)) elif op == "CALLER": stk.append(utils.coerce_to_int(msg.sender)) elif op == "CALLVALUE": stk.append(msg.value) elif op == "CALLDATALOAD": s0 = stk.pop() if s0 >= len(msg.data): stk.append(0) else: dat = msg.data[s0 : s0 + 32] stk.append(utils.big_endian_to_int(dat + "\x00" * (32 - len(dat)))) elif op == "CALLDATASIZE": stk.append(len(msg.data)) elif op == "CALLDATACOPY": s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0 + s2): return OUT_OF_GAS for i in range(s2): if s1 + i < len(msg.data): mem[s0 + i] = ord(msg.data[s1 + i]) else: mem[s0 + i] = 0 elif op == "GASPRICE": stk.append(tx.gasprice) elif op == "CODECOPY": s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0 + s2): return OUT_OF_GAS for i in range(s2): if s1 + i < len(processed_code): mem[s0 + i] = processed_code[s1 + i][-1] else: mem[s0 + i] = 0 elif op == "EXTCODESIZE": stk.append(len(block.get_code(stk.pop()) or "")) elif op == "EXTCODECOPY": addr, s1, s2, s3 = stk.pop(), stk.pop(), stk.pop(), stk.pop() extcode = block.get_code(addr) or "" if not mem_extend(mem, compustate, op, s1 + s3): return OUT_OF_GAS for i in range(s3): if s2 + i < len(extcode): mem[s1 + i] = ord(extcode[s2 + i]) else: mem[s1 + i] = 0 elif op == "PREVHASH": stk.append(utils.big_endian_to_int(block.prevhash)) elif op == "COINBASE": stk.append(utils.big_endian_to_int(block.coinbase.decode("hex"))) elif op == "TIMESTAMP": stk.append(block.timestamp) elif op == "NUMBER": stk.append(block.number) elif op == "DIFFICULTY": stk.append(block.difficulty) elif op == "GASLIMIT": stk.append(block.gas_limit) elif op == "POP": stk.pop() elif op == "MLOAD": s0 = stk.pop() if not mem_extend(mem, compustate, op, s0 + 32): return OUT_OF_GAS data = "".join(map(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 OUT_OF_GAS 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 OUT_OF_GAS mem[s0] = s1 % 256 elif op == "SLOAD": stk.append(block.get_storage_data(msg.to, stk.pop())) elif op == "SSTORE": s0, s1 = stk.pop(), stk.pop() pre_occupied = GSTORAGE if block.get_storage_data(msg.to, s0) else 0 post_occupied = GSTORAGE if s1 else 0 gascost = GSTORAGE + post_occupied - pre_occupied if compustate.gas < gascost: out_of_gas_exception("sstore trie expansion", gascost, compustate, op) compustate.gas -= gascost block.set_storage_data(msg.to, s0, s1) elif op == "JUMP": compustate.pc = stk.pop() elif op == "JUMPI": s0, s1 = stk.pop(), stk.pop() if s1: compustate.pc = s0 elif op == "PC": stk.append(compustate.pc) 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:]) dat = [x[-1] for x in processed_code[compustate.pc : compustate.pc + pushnum]] compustate.pc += pushnum stk.append(utils.bytearray_to_int(dat)) elif op[:3] == "DUP": depth = int(op[3:]) # DUP POP POP Debug hint is_debug = 1 for i in range(depth): if compustate.pc + i < len(processed_code) and processed_code[compustate.pc + i][0] != "POP": is_debug = 0 break if is_debug: stackargs = [stk.pop() for i in range(depth)] print (" ".join(map(repr, stackargs))) stk.extend(reversed(stackargs)) stk.append(stackargs[-1]) else: 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 == "CREATE": value, mstart, msz = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart + msz): return OUT_OF_GAS data = "".join(map(chr, mem[mstart : mstart + msz])) pblogger.log("SUB CONTRACT NEW", sender=msg.to, value=value, data=data.encode("hex")) create_msg = Message(msg.to, "", value, compustate.gas, data) addr, gas, code = create_contract(block, tx, create_msg) pblogger.log("SUB CONTRACT OUT", address=addr, code=code) if addr: stk.append(addr) compustate.gas = gas else: stk.append(0) compustate.gas = 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(), ) new_memsize = max(meminstart + meminsz, memoutstart + memoutsz) if not mem_extend(mem, compustate, op, new_memsize): return OUT_OF_GAS if compustate.gas < gas: return out_of_gas_exception("subcall gas", gas, compustate, op) compustate.gas -= gas to = utils.encode_int(to) to = (("\x00" * (32 - len(to))) + to)[12:].encode("hex") data = "".join(map(chr, mem[meminstart : meminstart + meminsz])) pblogger.log("SUB CALL NEW", sender=msg.to, to=to, value=value, gas=gas, data=data.encode("hex")) call_msg = Message(msg.to, to, value, gas, data) result, gas, data = apply_msg_send(block, tx, call_msg) pblogger.log("SUB CALL OUT", result=result, data=data, length=len(data), expected=memoutsz) 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] elif op == "RETURN": s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0 + s1): return OUT_OF_GAS return mem[s0 : s0 + s1] elif op == "POST": gas, to, value, meminstart, meminsz = stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, meminstart + meminsz): return OUT_OF_GAS if compustate.gas < gas: return out_of_gas_exception("subcall gas", gas, compustate, op) compustate.gas -= gas to = utils.encode_int(to) to = (("\x00" * (32 - len(to))) + to)[12:].encode("hex") data = "".join(map(chr, mem[meminstart : meminstart + meminsz])) pblogger.log("POST NEW", sender=msg.to, to=to, value=value, gas=gas, data=data.encode("hex")) post_msg = Message(msg.to, to, value, gas, data) block.postqueue.append(post_msg) elif op == "CALL_STATELESS": gas, to, value, meminstart, meminsz, memoutstart, memoutsz = ( stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), ) new_memsize = max(meminstart + meminsz, memoutstart + memoutsz) if not mem_extend(mem, compustate, op, new_memsize): return OUT_OF_GAS if compustate.gas < gas: return out_of_gas_exception("subcall gas", gas, compustate, op) compustate.gas -= gas to = utils.encode_int(to) to = (("\x00" * (32 - len(to))) + to)[12:].encode("hex") data = "".join(map(chr, mem[meminstart : meminstart + meminsz])) pblogger.log("SUB CALL NEW", sender=msg.to, to=to, value=value, gas=gas, data=data.encode("hex")) call_msg = Message(msg.to, msg.to, value, gas, data) result, gas, data = apply_msg(block, tx, call_msg, block.get_code(to)) pblogger.log("SUB CALL OUT", result=result, data=data, length=len(data), expected=memoutsz) 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] elif op == "SUICIDE": to = utils.encode_int(stk.pop()) to = (("\x00" * (32 - len(to))) + to)[12:].encode("hex") block.transfer_value(msg.to, to, block.get_balance(msg.to)) block.suicides.append(msg.to) return [] for a in stk: assert isinstance(a, (int, long))
def check_proof_of_work(self, nonce): prefix = self.serialize_header_without_nonce() h = utils.sha3(utils.sha3(prefix + nonce)) l256 = utils.big_endian_to_int(h) return l256 < 2 ** 256 / self.difficulty
def apply_op(block, tx, msg, processed_code, compustate): if compustate.pc >= len(processed_code): return [] op, in_args, out_args, mem_grabs, fee, opcode = processed_code[ compustate.pc] # empty stack error if in_args > len(compustate.stack): pblogger.log('INSUFFICIENT STACK ERROR', op=op, needed=in_args, available=len(compustate.stack)) return [] # out of gas error if fee > compustate.gas: return out_of_gas_exception('base_gas', fee, compustate, op) if pblogger.log_apply_op: if pblogger.log_stack: pblogger.log('STK', stk=list(reversed(compustate.stack))) if pblogger.log_memory: for i in range(0, len(compustate.memory), 16): memblk = compustate.memory[i:i + 16] memline = ' '.join([chr(x).encode('hex') for x in memblk]) pblogger.log('MEM', mem=memline) if pblogger.log_storage: pblogger.log('STORAGE', storage=block.account_to_dict(msg.to)['storage']) if pblogger.log_op: log_args = dict(pc=compustate.pc, op=op, stackargs=compustate.stack[-1:-in_args - 1:-1], gas=compustate.gas) if op[:4] == 'PUSH': ind = compustate.pc + 1 log_args['value'] = \ utils.bytearray_to_int([x[-1] for x in processed_code[ind: ind + int(op[4:])]]) elif op == 'CALLDATACOPY': log_args['data'] = msg.data.encode('hex') pblogger.log('OP', **log_args) # Apply operation compustate.gas -= fee compustate.pc += 1 stk = compustate.stack mem = compustate.memory if op == 'STOP' or op == 'INVALID': return [] elif op == 'ADD': stk.append((stk.pop() + stk.pop()) % TT256) elif op == 'SUB': stk.append((stk.pop() - stk.pop()) % TT256) elif op == 'MUL': stk.append((stk.pop() * stk.pop()) % TT256) 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 = to_signed(stk.pop()), to_signed(stk.pop()) stk.append(0 if s1 == 0 else (s0 / s1) % TT256) elif op == 'SMOD': s0, s1 = to_signed(stk.pop()), to_signed(stk.pop()) stk.append(0 if s1 == 0 else (s0 % s1) % TT256) elif op == 'EXP': stk.append(pow(stk.pop(), stk.pop(), TT256)) elif op == 'NEG': stk.append(-stk.pop() % TT256) elif 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 = to_signed(stk.pop()), to_signed(stk.pop()) stk.append(1 if s0 < s1 else 0) elif op == 'SGT': s0, s1 = to_signed(stk.pop()), 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 == 'NOT': 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 == 'BYTE': s0, s1 = stk.pop(), stk.pop() if s0 >= 32: stk.append(0) else: stk.append((s1 / 256**(31 - s0)) % 256) 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 == 'SHA3': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0 + s1): return OUT_OF_GAS data = ''.join(map(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': stk.append(block.get_balance(utils.coerce_addr_to_hex(stk.pop()))) elif op == 'ORIGIN': stk.append(utils.coerce_to_int(tx.sender)) elif op == 'CALLER': stk.append(utils.coerce_to_int(msg.sender)) elif op == 'CALLVALUE': stk.append(msg.value) elif op == 'CALLDATALOAD': s0 = stk.pop() if s0 >= len(msg.data): stk.append(0) else: dat = msg.data[s0:s0 + 32] stk.append(utils.big_endian_to_int(dat + '\x00' * (32 - len(dat)))) elif op == 'CALLDATASIZE': stk.append(len(msg.data)) elif op == 'CALLDATACOPY': s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0 + s2): return OUT_OF_GAS for i in range(s2): if s1 + i < len(msg.data): mem[s0 + i] = ord(msg.data[s1 + i]) else: mem[s0 + i] = 0 elif op == 'GASPRICE': stk.append(tx.gasprice) elif op == 'CODECOPY': s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0 + s2): return OUT_OF_GAS for i in range(s2): if s1 + i < len(processed_code): mem[s0 + i] = processed_code[s1 + i][-1] else: mem[s0 + i] = 0 elif op == 'EXTCODESIZE': stk.append(len(block.get_code(stk.pop()) or '')) elif op == 'EXTCODECOPY': addr, s1, s2, s3 = stk.pop(), stk.pop(), stk.pop(), stk.pop() extcode = block.get_code(addr) or '' if not mem_extend(mem, compustate, op, s1 + s3): return OUT_OF_GAS for i in range(s3): if s2 + i < len(extcode): mem[s1 + i] = ord(extcode[s2 + i]) else: mem[s1 + i] = 0 elif op == 'PREVHASH': stk.append(utils.big_endian_to_int(block.prevhash)) elif op == 'COINBASE': stk.append(utils.big_endian_to_int(block.coinbase.decode('hex'))) elif op == 'TIMESTAMP': stk.append(block.timestamp) elif op == 'NUMBER': stk.append(block.number) elif op == 'DIFFICULTY': stk.append(block.difficulty) elif op == 'GASLIMIT': stk.append(block.gas_limit) elif op == 'POP': stk.pop() elif op == 'MLOAD': s0 = stk.pop() if not mem_extend(mem, compustate, op, s0 + 32): return OUT_OF_GAS data = ''.join(map(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 OUT_OF_GAS 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 OUT_OF_GAS mem[s0] = s1 % 256 elif op == 'SLOAD': stk.append(block.get_storage_data(msg.to, stk.pop())) elif op == 'SSTORE': s0, s1 = stk.pop(), stk.pop() pre_occupied = GSTORAGE if block.get_storage_data(msg.to, s0) else 0 post_occupied = GSTORAGE if s1 else 0 gascost = GSTORAGE + post_occupied - pre_occupied if compustate.gas < gascost: out_of_gas_exception('sstore trie expansion', gascost, compustate, op) compustate.gas -= gascost block.set_storage_data(msg.to, s0, s1) elif op == 'JUMP': compustate.pc = stk.pop() elif op == 'JUMPI': s0, s1 = stk.pop(), stk.pop() if s1: compustate.pc = s0 elif op == 'PC': stk.append(compustate.pc) 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:]) dat = [ x[-1] for x in processed_code[compustate.pc:compustate.pc + pushnum] ] compustate.pc += pushnum stk.append(utils.bytearray_to_int(dat)) elif op[:3] == 'DUP': depth = int(op[3:]) # DUP POP POP Debug hint is_debug = 1 for i in range(depth): if compustate.pc + i < len(processed_code) and \ processed_code[compustate.pc + i][0] != 'POP': is_debug = 0 break if is_debug: stackargs = [stk.pop() for i in range(depth)] print(' '.join(map(repr, stackargs))) stk.extend(reversed(stackargs)) stk.append(stackargs[-1]) else: 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 == 'CREATE': value, mstart, msz = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart + msz): return OUT_OF_GAS data = ''.join(map(chr, mem[mstart:mstart + msz])) pblogger.log('SUB CONTRACT NEW', sender=msg.to, value=value, data=data.encode('hex')) create_msg = Message(msg.to, '', value, compustate.gas, data) addr, gas, code = create_contract(block, tx, create_msg) pblogger.log('SUB CONTRACT OUT', address=addr, code=code) if addr: stk.append(addr) compustate.gas = gas else: stk.append(0) compustate.gas = 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() new_memsize = max(meminstart + meminsz, memoutstart + memoutsz) if not mem_extend(mem, compustate, op, new_memsize): return OUT_OF_GAS if compustate.gas < gas: return out_of_gas_exception('subcall gas', gas, compustate, op) compustate.gas -= gas to = utils.encode_int(to) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') data = ''.join(map(chr, mem[meminstart:meminstart + meminsz])) pblogger.log('SUB CALL NEW', sender=msg.to, to=to, value=value, gas=gas, data=data.encode('hex')) call_msg = Message(msg.to, to, value, gas, data) result, gas, data = apply_msg_send(block, tx, call_msg) pblogger.log('SUB CALL OUT', result=result, data=data, length=len(data), expected=memoutsz) 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] elif op == 'RETURN': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0 + s1): return OUT_OF_GAS return mem[s0:s0 + s1] elif op == 'POST': gas, to, value, meminstart, meminsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, meminstart + meminsz): return OUT_OF_GAS if compustate.gas < gas: return out_of_gas_exception('subcall gas', gas, compustate, op) compustate.gas -= gas to = utils.encode_int(to) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') data = ''.join(map(chr, mem[meminstart:meminstart + meminsz])) pblogger.log('POST NEW', sender=msg.to, to=to, value=value, gas=gas, data=data.encode('hex')) post_msg = Message(msg.to, to, value, gas, data) block.postqueue.append(post_msg) elif op == 'CALL_STATELESS': gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() new_memsize = max(meminstart + meminsz, memoutstart + memoutsz) if not mem_extend(mem, compustate, op, new_memsize): return OUT_OF_GAS if compustate.gas < gas: return out_of_gas_exception('subcall gas', gas, compustate, op) compustate.gas -= gas to = utils.encode_int(to) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') data = ''.join(map(chr, mem[meminstart:meminstart + meminsz])) pblogger.log('SUB CALL NEW', sender=msg.to, to=to, value=value, gas=gas, data=data.encode('hex')) call_msg = Message(msg.to, msg.to, value, gas, data) result, gas, data = apply_msg(block, tx, call_msg, block.get_code(to)) pblogger.log('SUB CALL OUT', result=result, data=data, length=len(data), expected=memoutsz) 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] elif op == 'SUICIDE': to = utils.encode_int(stk.pop()) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') block.transfer_value(msg.to, to, block.get_balance(msg.to)) block.suicides.append(msg.to) return [] for a in stk: assert isinstance(a, (int, long))
def __hash__(self): return utils.big_endian_to_int(str_to_bytes(self.__repr__()))
def OP_PREVHASH(): stk.append(utils.big_endian_to_int(block.prevhash))
def get_refcount(self, key): try: return utils.big_endian_to_int(self.db.get(key)[:4]) except KeyError: return 0
def apply_op(block, tx, msg, code, compustate): op, in_args, out_args = get_op_data(code, compustate.pc) # empty stack error if in_args > len(compustate.stack): return [] # out of gas error fee = calcfee(block, tx, msg, compustate, op) if fee > compustate.gas: if debug: print("Out of gas", compustate.gas, "need", fee) print(op, list(reversed(compustate.stack))) return OUT_OF_GAS stackargs = [] for i in range(in_args): stackargs.append(compustate.stack.pop()) if debug: import serpent if op[:4] == 'PUSH': start, n = compustate.pc + 1, int(op[4:]) print(op, utils.big_endian_to_int(code[start:start + n])) else: print(op, ' '.join(map(str, stackargs)), serpent.decode_datalist(compustate.memory)) # Apply operation oldgas = compustate.gas oldpc = compustate.pc compustate.gas -= fee compustate.pc += 1 stk = compustate.stack mem = compustate.memory if op == 'STOP': return [] elif op == 'ADD': stk.append((stackargs[0] + stackargs[1]) % 2 ** 256) elif op == 'SUB': stk.append((stackargs[0] - stackargs[1]) % 2 ** 256) elif op == 'MUL': stk.append((stackargs[0] * stackargs[1]) % 2 ** 256) elif op == 'DIV': if stackargs[1] == 0: return [] stk.append(stackargs[0] / stackargs[1]) elif op == 'MOD': if stackargs[1] == 0: return [] stk.append(stackargs[0] % stackargs[1]) elif op == 'SDIV': if stackargs[1] == 0: return [] if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append((stackargs[0] / stackargs[1]) % 2 ** 256) elif op == 'SMOD': if stackargs[1] == 0: return [] if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append((stackargs[0] % stackargs[1]) % 2 ** 256) elif op == 'EXP': stk.append(pow(stackargs[0], stackargs[1], 2 ** 256)) elif op == 'NEG': stk.append(2 ** 256 - stackargs[0]) elif op == 'LT': stk.append(1 if stackargs[0] < stackargs[1] else 0) elif op == 'GT': stk.append(1 if stackargs[0] > stackargs[1] else 0) elif op == 'SLT': if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append(1 if stackargs[0] < stackargs[1] else 0) elif op == 'SGT': if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append(1 if stackargs[0] > stackargs[1] else 0) elif op == 'EQ': stk.append(1 if stackargs[0] == stackargs[1] else 0) elif op == 'NOT': stk.append(0 if stackargs[0] else 1) elif op == 'AND': stk.append(stackargs[0] & stackargs[1]) elif op == 'OR': stk.append(stackargs[0] | stackargs[1]) elif op == 'XOR': stk.append(stackargs[0] ^ stackargs[1]) elif op == 'BYTE': if stackargs[0] >= 32: stk.append(0) else: stk.append((stackargs[1] / 256 ** stackargs[0]) % 256) elif op == 'SHA3': if len(mem) < ceil32(stackargs[0] + stackargs[1]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[1]) - len(mem))) data = ''.join(map(chr, mem[stackargs[0]:stackargs[0] + stackargs[1]])) print 'data time!' print data print data.encode('hex') stk.append(int(utils.sha3(data).encode('hex'), 16)) elif op == 'ECVERIFY': # parameters: msg_hash (32), v (32), r (32), s (32), pubX (32), pubY (32) # stack should have all args msg_hash, v, r, s, pubX, pubY = stackargs pubX = utils.int_to_big_endian(pubX).encode('hex') pubY = utils.int_to_big_endian(pubY).encode('hex') msg_hash = utils.int_to_big_endian(msg_hash) pub = ('04' + pubX + pubY).decode('hex') verified = ecdsa_raw_verify(msg_hash, (v, r, s), pub) print 'verified: ', verified stk.append(verified) elif op == 'ECRECOVER': # parameters: msg_hash (32), v (32), r (32), s (32), p (64 - empty array to hold pubkey) # stack should have all args msg_hash, v, r, s = stackargs msg_hash = utils.int_to_big_endian(msg_hash) pubX, pubY = ecdsa_raw_recover(msg_hash, (v, r, s)) stk.append(pubX) stk.append(pubY) elif op == 'PUB2ADDR': pubX, pubY = stackargs pubX = utils.int_to_big_endian(pubX).encode('hex') pubY = utils.int_to_big_endian(pubY).encode('hex') pub = pubX + pubY pub = pub.decode('hex') addr = utils.sha3(pub)[12:] stk.append(addr) elif op == 'ADDRESS': stk.append(msg.to) elif op == 'BALANCE': stk.append(block.get_balance(msg.to)) elif op == 'ORIGIN': stk.append(tx.sender) elif op == 'CALLER': stk.append(utils.coerce_to_int(msg.sender)) elif op == 'CALLVALUE': stk.append(msg.value) elif op == 'CALLDATALOAD': if stackargs[0] >= len(msg.data): stk.append(0) else: dat = msg.data[stackargs[0]:stackargs[0] + 32] stk.append(utils.big_endian_to_int(dat + '\x00' * (32 - len(dat)))) elif op == 'CALLDATASIZE': stk.append(len(msg.data)) elif op == 'CALLDATACOPY': if len(mem) < ceil32(stackargs[1] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[1] + stackargs[2]) - len(mem))) for i in range(stackargs[2]): if stackargs[0] + i < len(msg.data): mem[stackargs[1] + i] = ord(msg.data[stackargs[0] + i]) else: mem[stackargs[1] + i] = 0 elif op == 'GASPRICE': stk.append(tx.gasprice) elif op == 'CODECOPY': if len(mem) < ceil32(stackargs[1] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[1] + stackargs[2]) - len(mem))) for i in range(stackargs[2]): if stackargs[0] + i < len(code): mem[stackargs[1] + i] = ord(code[stackargs[0] + i]) else: mem[stackargs[1] + i] = 0 elif op == 'PREVHASH': stk.append(utils.big_endian_to_int(block.prevhash)) elif op == 'COINBASE': stk.append(utils.big_endian_to_int(block.coinbase.decode('hex'))) elif op == 'TIMESTAMP': stk.append(block.timestamp) elif op == 'NUMBER': stk.append(block.number) elif op == 'DIFFICULTY': stk.append(block.difficulty) elif op == 'GASLIMIT': stk.append(block.gaslimit) elif op == 'POP': pass elif op == 'DUP': stk.append(stackargs[0]) stk.append(stackargs[0]) elif op == 'SWAP': stk.append(stackargs[0]) stk.append(stackargs[1]) elif op == 'MLOAD': if len(mem) < ceil32(stackargs[0] + 32): mem.extend([0] * (ceil32(stackargs[0] + 32) - len(mem))) data = ''.join(map(chr, mem[stackargs[0]:stackargs[0] + 32])) stk.append(utils.big_endian_to_int(data)) elif op == 'MSTORE': if len(mem) < ceil32(stackargs[0] + 32): mem.extend([0] * (ceil32(stackargs[0] + 32) - len(mem))) v = stackargs[1] #if isinstance(v, str): # v = int(v.encode('hex'), 16) for i in range(31, -1, -1): mem[stackargs[0] + i] = v % 256 v /= 256 elif op == 'MSTORE8': if len(mem) < ceil32(stackargs[0] + 1): mem.extend([0] * (ceil32(stackargs[0] + 1) - len(mem))) mem[stackargs[0]] = stackargs[1] % 256 elif op == 'SLOAD': stk.append(block.get_storage_data(msg.to, stackargs[0])) elif op == 'SSTORE': block.set_storage_data(msg.to, stackargs[0], stackargs[1]) elif op == 'JUMP': compustate.pc = stackargs[0] elif op == 'JUMPI': if stackargs[1]: compustate.pc = stackargs[0] elif op == 'PC': stk.append(compustate.pc) elif op == 'MSIZE': stk.append(len(mem)) elif op == 'GAS': stk.append(oldgas) elif op[:4] == 'PUSH': pushnum = int(op[4:]) compustate.pc = oldpc + 1 + pushnum dat = code[oldpc + 1: oldpc + 1 + pushnum] stk.append(utils.big_endian_to_int(dat)) elif op == 'CREATE': if len(mem) < ceil32(stackargs[2] + stackargs[3]): mem.extend([0] * (ceil32(stackargs[2] + stackargs[3]) - len(mem))) gas = stackargs[0] value = stackargs[1] data = ''.join(map(chr, mem[stackargs[2]:stackargs[2] + stackargs[3]])) if debug: print("Sub-contract:", msg.to, value, gas, data) addr, gas, code = create_contract( block, tx, Message(msg.to, '', value, gas, data)) if debug: print("Output of contract creation:", addr, code) if addr: stk.append(utils.coerce_to_int(addr)) else: stk.append(0) elif op == 'CALL': if len(mem) < ceil32(stackargs[3] + stackargs[4]): mem.extend([0] * (ceil32(stackargs[3] + stackargs[4]) - len(mem))) if len(mem) < ceil32(stackargs[5] + stackargs[6]): mem.extend([0] * (ceil32(stackargs[5] + stackargs[6]) - len(mem))) gas = stackargs[0] to = utils.encode_int(stackargs[1]) to = (('\x00' * (32 - len(to))) + to)[12:] value = stackargs[2] data = ''.join(map(chr, mem[stackargs[3]:stackargs[3] + stackargs[4]])) if debug: print("Sub-call:", utils.coerce_addr_to_hex(msg.to), utils.coerce_addr_to_hex(to), value, gas, data) result, gas, data = apply_msg( block, tx, Message(msg.to, to, value, gas, data)) if debug: print("Output of sub-call:", result, data, "length", len(data), "expected", stackargs[6]) for i in range(stackargs[6]): mem[stackargs[5] + i] = 0 if result == 0: stk.append(0) else: stk.append(1) compustate.gas += gas for i in range(len(data)): mem[stackargs[5] + i] = data[i] elif op == 'RETURN': if len(mem) < ceil32(stackargs[0] + stackargs[1]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[1]) - len(mem))) return mem[stackargs[0]:stackargs[0] + stackargs[1]] elif op == 'SUICIDE': to = utils.encode_int(stackargs[0]) to = (('\x00' * (32 - len(to))) + to)[12:] block.delta_balance(to, block.get_balance(msg.to)) block.state.update(msg.to, '') return []
def sub1(b): v = utils.big_endian_to_int(b) return utils.zpad(utils.encode_int(v - 1), 4)
def add1(b): v = utils.big_endian_to_int(b) return utils.zpad(utils.encode_int(v + 1), 4)
def apply_op(block, tx, msg, code, compustate): op, in_args, out_args, mem_grabs, base_gas = opdata = get_op_data(code, compustate.pc) # empty stack error if in_args > len(compustate.stack): pblogger.log('INSUFFICIENT STACK ERROR', op=op, needed=in_args, available=len(compustate.stack)) return [] # out of gas error fee = calcfee(block, tx, msg, compustate, opdata) if fee > compustate.gas: pblogger.log('OUT OF GAS', needed=fee, available=compustate.gas, op=op, stack=list(reversed(compustate.stack))) return OUT_OF_GAS stackargs = [] for i in range(in_args): stackargs.append(compustate.stack.pop()) if pblogger.log_op: log_args = dict(pc=compustate.pc, op=op, stackargs=stackargs, gas=compustate.gas) if op[:4] == 'PUSH': ind = compustate.pc + 1 log_args['value'] = utils.big_endian_to_int(code[ind: ind + int(op[4:])]) elif op == 'CALLDATACOPY': log_args['data'] = msg.data.encode('hex') pblogger.log('OP', **log_args) if pblogger.log_memory: for i in range(0, len(compustate.memory), 16): memblk = compustate.memory[i:i+16] memline = ' '.join([chr(x).encode('hex') for x in memblk]) pblogger.log('MEM', mem=memline) # Apply operation oldpc = compustate.pc compustate.gas -= fee compustate.pc += 1 stk = compustate.stack mem = compustate.memory if op == 'STOP' or op == 'INVALID': return [] elif op == 'ADD': stk.append((stackargs[0] + stackargs[1]) % 2 ** 256) elif op == 'SUB': stk.append((stackargs[0] - stackargs[1]) % 2 ** 256) elif op == 'MUL': stk.append((stackargs[0] * stackargs[1]) % 2 ** 256) elif op == 'DIV': stk.append(0 if stackargs[1] == 0 else stackargs[0] / stackargs[1]) elif op == 'MOD': stk.append(0 if stackargs[1] == 0 else stackargs[0] % stackargs[1]) elif op == 'SDIV': if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append(0 if stackargs[1] == 0 else (stackargs[0] / stackargs[1]) % 2 ** 256) elif op == 'SMOD': if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append(0 if stackargs[1] == 0 else (stackargs[0] % stackargs[1]) % 2 ** 256) elif op == 'EXP': stk.append(pow(stackargs[0], stackargs[1], 2 ** 256)) elif op == 'NEG': stk.append(-stackargs[0] % 2**256) elif op == 'LT': stk.append(1 if stackargs[0] < stackargs[1] else 0) elif op == 'GT': stk.append(1 if stackargs[0] > stackargs[1] else 0) elif op == 'SLT': if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append(1 if stackargs[0] < stackargs[1] else 0) elif op == 'SGT': if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append(1 if stackargs[0] > stackargs[1] else 0) elif op == 'EQ': stk.append(1 if stackargs[0] == stackargs[1] else 0) elif op == 'NOT': stk.append(0 if stackargs[0] else 1) elif op == 'AND': stk.append(stackargs[0] & stackargs[1]) elif op == 'OR': stk.append(stackargs[0] | stackargs[1]) elif op == 'XOR': stk.append(stackargs[0] ^ stackargs[1]) elif op == 'BYTE': if stackargs[0] >= 32: stk.append(0) else: stk.append((stackargs[1] / 256 ** (31 - stackargs[0])) % 256) elif op == 'ADDMOD': stk.append((stackargs[0] + stackargs[1]) % stackargs[2] if stackargs[2] else 0) elif op == 'MULMOD': stk.append((stackargs[0] * stackargs[1]) % stackargs[2] if stackargs[2] else 0) elif op == 'SHA3': if stackargs[1] and len(mem) < ceil32(stackargs[0] + stackargs[1]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[1]) - len(mem))) data = ''.join(map(chr, mem[stackargs[0]:stackargs[0] + stackargs[1]])) stk.append(utils.big_endian_to_int(utils.sha3(data))) elif op == 'ADDRESS': stk.append(utils.coerce_to_int(msg.to)) elif op == 'BALANCE': stk.append(block.get_balance(utils.coerce_addr_to_hex(stackargs[0]))) elif op == 'ORIGIN': stk.append(utils.coerce_to_int(tx.sender)) elif op == 'CALLER': stk.append(utils.coerce_to_int(msg.sender)) elif op == 'CALLVALUE': stk.append(msg.value) elif op == 'CALLDATALOAD': if stackargs[0] >= len(msg.data): stk.append(0) else: dat = msg.data[stackargs[0]:stackargs[0] + 32] stk.append(utils.big_endian_to_int(dat + '\x00' * (32 - len(dat)))) elif op == 'CALLDATASIZE': stk.append(len(msg.data)) elif op == 'CALLDATACOPY': if stackargs[2] and len(mem) < ceil32(stackargs[0] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[2]) - len(mem))) for i in range(stackargs[2]): if stackargs[1] + i < len(msg.data): mem[stackargs[0] + i] = ord(msg.data[stackargs[1] + i]) else: mem[stackargs[0] + i] = 0 elif op == 'GASPRICE': stk.append(tx.gasprice) elif op == 'CODECOPY': if stackargs[2] and len(mem) < ceil32(stackargs[0] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[2]) - len(mem))) for i in range(stackargs[2]): if stackargs[1] + i < len(code): mem[stackargs[0] + i] = ord(code[stackargs[1] + i]) else: mem[stackargs[0] + i] = 0 elif op == 'PREVHASH': stk.append(utils.big_endian_to_int(block.prevhash)) elif op == 'COINBASE': stk.append(utils.big_endian_to_int(block.coinbase.decode('hex'))) elif op == 'TIMESTAMP': stk.append(block.timestamp) elif op == 'NUMBER': stk.append(block.number) elif op == 'DIFFICULTY': stk.append(block.difficulty) elif op == 'GASLIMIT': stk.append(block.gas_limit) elif op == 'POP': pass elif op == 'SWAP': stk.append(stackargs[0]) stk.append(stackargs[1]) elif op == 'MLOAD': if len(mem) < ceil32(stackargs[0] + 32): mem.extend([0] * (ceil32(stackargs[0] + 32) - len(mem))) data = ''.join(map(chr, mem[stackargs[0]:stackargs[0] + 32])) stk.append(utils.big_endian_to_int(data)) elif op == 'MSTORE': if len(mem) < ceil32(stackargs[0] + 32): mem.extend([0] * (ceil32(stackargs[0] + 32) - len(mem))) v = stackargs[1] for i in range(31, -1, -1): mem[stackargs[0] + i] = v % 256 v /= 256 elif op == 'MSTORE8': if len(mem) < ceil32(stackargs[0] + 1): mem.extend([0] * (ceil32(stackargs[0] + 1) - len(mem))) mem[stackargs[0]] = stackargs[1] % 256 elif op == 'SLOAD': stk.append(block.get_storage_data(msg.to, stackargs[0])) elif op == 'SSTORE': block.set_storage_data(msg.to, stackargs[0], stackargs[1]) elif op == 'JUMP': compustate.pc = stackargs[0] elif op == 'JUMPI': if stackargs[1]: compustate.pc = stackargs[0] elif op == 'PC': stk.append(compustate.pc) 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 = oldpc + 1 + pushnum dat = code[oldpc + 1: oldpc + 1 + pushnum] stk.append(utils.big_endian_to_int(dat)) elif op[:3] == 'DUP': # DUP POP POP Debug hint is_debug = 1 for i in range(len(stackargs)): if get_op_data(code, oldpc + i + 1)[0] != 'POP': is_debug = 0 break if is_debug: print(' '.join(map(repr, stackargs))) pblogger.log('DEBUG', vals=stackargs) compustate.pc = oldpc + 2 + len(stackargs) else: stk.extend(reversed(stackargs)) stk.append(stackargs[-1]) elif op[:4] == 'SWAP': stk.append(stackargs[0]) stk.extend(reversed(stackargs[1:-1])) stk.append(stackargs[-1]) elif op == 'CREATE': if stackargs[2] and len(mem) < ceil32(stackargs[1] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[1] + stackargs[2]) - len(mem))) value = stackargs[0] data = ''.join(map(chr, mem[stackargs[1]:stackargs[1] + stackargs[2]])) pblogger.log('SUB CONTRACT NEW', sender=msg.to, value=value, data=data.encode('hex')) create_msg = Message(msg.to, '', value, compustate.gas, data) addr, gas, code = create_contract(block, tx, create_msg) pblogger.log('SUB CONTRACT OUT', address=addr, code=code) if addr: stk.append(addr) compustate.gas = gas else: stk.append(0) compustate.gas = 0 elif op == 'CALL': if stackargs[4] and len(mem) < ceil32(stackargs[3] + stackargs[4]): mem.extend([0] * (ceil32(stackargs[3] + stackargs[4]) - len(mem))) if stackargs[6] and len(mem) < ceil32(stackargs[5] + stackargs[6]): mem.extend([0] * (ceil32(stackargs[5] + stackargs[6]) - len(mem))) gas = stackargs[0] to = utils.encode_int(stackargs[1]) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') value = stackargs[2] data = ''.join(map(chr, mem[stackargs[3]:stackargs[3] + stackargs[4]])) pblogger.log('SUB CALL NEW', sender=msg.to, to=to, value=value, gas=gas, data=data.encode('hex')) call_msg = Message(msg.to, to, value, gas, data) result, gas, data = apply_msg_send(block, tx, call_msg) pblogger.log('SUB CALL OUT', result=result, data=data, length=len(data), expected=stackargs[6]) if result == 0: stk.append(0) else: stk.append(1) compustate.gas += gas for i in range(min(len(data), stackargs[6])): mem[stackargs[5] + i] = data[i] elif op == 'RETURN': if stackargs[1] and len(mem) < ceil32(stackargs[0] + stackargs[1]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[1]) - len(mem))) return mem[stackargs[0]:stackargs[0] + stackargs[1]] elif op == 'POST': if stackargs[4] and len(mem) < ceil32(stackargs[3] + stackargs[4]): mem.extend([0] * (ceil32(stackargs[3] + stackargs[4]) - len(mem))) gas = stackargs[0] to = utils.encode_int(stackargs[1]) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') value = stackargs[2] data = ''.join(map(chr, mem[stackargs[3]:stackargs[3] + stackargs[4]])) pblogger.log('POST NEW', sender=msg.to, to=to, value=value, gas=gas, data=data.encode('hex')) post_msg = Message(msg.to, to, value, gas, data) block.postqueue.append(post_msg) elif op == 'CALL_STATELESS': if stackargs[4] and len(mem) < ceil32(stackargs[3] + stackargs[4]): mem.extend([0] * (ceil32(stackargs[3] + stackargs[4]) - len(mem))) if stackargs[6] and len(mem) < ceil32(stackargs[5] + stackargs[6]): mem.extend([0] * (ceil32(stackargs[5] + stackargs[6]) - len(mem))) gas = stackargs[0] to = utils.encode_int(stackargs[1]) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') value = stackargs[2] data = ''.join(map(chr, mem[stackargs[3]:stackargs[3] + stackargs[4]])) pblogger.log('SUB CALL NEW', sender=msg.to, to=to, value=value, gas=gas, data=data.encode('hex')) call_msg = Message(msg.to, msg.to, value, gas, data) result, gas, data = apply_msg(block, tx, call_msg, block.get_code(to)) pblogger.log('SUB CALL OUT', result=result, data=data, length=len(data), expected=stackargs[6]) if result == 0: stk.append(0) else: stk.append(1) compustate.gas += gas for i in range(min(len(data), stackargs[6])): mem[stackargs[5] + i] = data[i] elif op == 'SUICIDE': to = utils.encode_int(stackargs[0]) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') block.transfer_value(msg.to, to, block.get_balance(msg.to)) block.suicides.append(msg.to) return [] for a in stk: assert isinstance(a, (int, long))
def apply_op(block, tx, msg, processed_code, compustate): if compustate.pc >= len(processed_code): return [] op, in_args, out_args, mem_grabs, fee, opcode = processed_code[compustate.pc] # empty stack error if in_args > len(compustate.stack): pblogger.log('INSUFFICIENT STACK ERROR', op=op, needed=in_args, available=len(compustate.stack)) return [] # out of gas error if fee > compustate.gas: return out_of_gas_exception('base_gas', fee, compustate, op) if pblogger.log_apply_op: if pblogger.log_stack: pblogger.log('STK', stk=list(reversed(compustate.stack))) if pblogger.log_op: log_args = dict(pc=compustate.pc, op=op, stackargs=compustate.stack[-1:-in_args-1:-1], gas=compustate.gas) if op[:4] == 'PUSH': ind = compustate.pc + 1 log_args['value'] = \ utils.bytearray_to_int([x[-1] for x in processed_code[ind: ind + int(op[4:])]]) elif op == 'CALLDATACOPY': log_args['data'] = msg.data.encode('hex') pblogger.log('OP', **log_args) if pblogger.log_memory: for i in range(0, len(compustate.memory), 16): memblk = compustate.memory[i:i+16] memline = ' '.join([chr(x).encode('hex') for x in memblk]) pblogger.log('MEM', mem=memline) # Apply operation compustate.gas -= fee compustate.pc += 1 stk = compustate.stack mem = compustate.memory if op == 'STOP' or op == 'INVALID': return [] elif op == 'ADD': stk.append((stk.pop() + stk.pop()) % TT256) elif op == 'SUB': stk.append((stk.pop() - stk.pop()) % TT256) elif op == 'MUL': stk.append((stk.pop() * stk.pop()) % TT256) 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 = to_signed(stk.pop()), to_signed(stk.pop()) stk.append(0 if s1 == 0 else (s0 / s1) % TT256) elif op == 'SMOD': s0, s1 = to_signed(stk.pop()), to_signed(stk.pop()) stk.append(0 if s1 == 0 else (s0 % s1) % TT256) elif op == 'EXP': stk.append(pow(stk.pop(), stk.pop(), TT256)) elif op == 'NEG': stk.append(-stk.pop() % TT256) elif 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 = to_signed(stk.pop()), to_signed(stk.pop()) stk.append(1 if s0 < s1 else 0) elif op == 'SGT': s0, s1 = to_signed(stk.pop()), 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 == 'NOT': 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 == 'BYTE': s0, s1 = stk.pop(), stk.pop() if s0 >= 32: stk.append(0) else: stk.append((s1 / 256 ** (31 - s0)) % 256) 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 == 'SHA3': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0 + s1): return OUT_OF_GAS data = ''.join(map(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': stk.append(block.get_balance(utils.coerce_addr_to_hex(stk.pop()))) elif op == 'ORIGIN': stk.append(utils.coerce_to_int(tx.sender)) elif op == 'CALLER': stk.append(utils.coerce_to_int(msg.sender)) elif op == 'CALLVALUE': stk.append(msg.value) elif op == 'CALLDATALOAD': s0 = stk.pop() if s0 >= len(msg.data): stk.append(0) else: dat = msg.data[s0: s0 + 32] stk.append(utils.big_endian_to_int(dat + '\x00' * (32 - len(dat)))) elif op == 'CALLDATASIZE': stk.append(len(msg.data)) elif op == 'CALLDATACOPY': s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0 + s2): return OUT_OF_GAS for i in range(s2): if s1 + i < len(msg.data): mem[s0 + i] = ord(msg.data[s1 + i]) else: mem[s0 + i] = 0 elif op == 'GASPRICE': stk.append(tx.gasprice) elif op == 'CODECOPY': s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0 + s2): return OUT_OF_GAS for i in range(s2): if s1 + i < len(processed_code): mem[s0 + i] = processed_code[s1 + i][-1] else: mem[s0 + i] = 0 elif op == 'EXTCODESIZE': stk.append(len(block.get_code(stk.pop()) or '')) elif op == 'EXTCODECOPY': addr, s1, s2, s3 = stk.pop(), stk.pop(), stk.pop(), stk.pop() extcode = block.get_code(addr) or '' if not mem_extend(mem, compustate, op, s1 + s3): return OUT_OF_GAS for i in range(s3): if s2 + i < len(extcode): mem[s1 + i] = ord(extcode[s2 + i]) else: mem[s1 + i] = 0 elif op == 'PREVHASH': stk.append(utils.big_endian_to_int(block.prevhash)) elif op == 'COINBASE': stk.append(utils.big_endian_to_int(block.coinbase.decode('hex'))) elif op == 'TIMESTAMP': stk.append(block.timestamp) elif op == 'NUMBER': stk.append(block.number) elif op == 'DIFFICULTY': stk.append(block.difficulty) elif op == 'GASLIMIT': stk.append(block.gas_limit) elif op == 'POP': stk.pop() elif op == 'MLOAD': s0 = stk.pop() if not mem_extend(mem, compustate, op, s0 + 32): return OUT_OF_GAS data = ''.join(map(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 OUT_OF_GAS 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 OUT_OF_GAS mem[s0] = s1 % 256 elif op == 'SLOAD': stk.append(block.get_storage_data(msg.to, stk.pop())) elif op == 'SSTORE': s0, s1 = stk.pop(), stk.pop() pre_occupied = GSTORAGE if block.get_storage_data(msg.to, s0) else 0 post_occupied = GSTORAGE if s1 else 0 gascost = GSTORAGE + post_occupied - pre_occupied if compustate.gas < gascost: out_of_gas_exception('sstore trie expansion', gascost, compustate, op) compustate.gas -= gascost block.set_storage_data(msg.to, s0, s1) elif op == 'JUMP': compustate.pc = stk.pop() elif op == 'JUMPI': s0, s1 = stk.pop(), stk.pop() if s1: compustate.pc = s0 elif op == 'PC': stk.append(compustate.pc) 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:]) dat = [x[-1] for x in processed_code[compustate.pc: compustate.pc + pushnum]] compustate.pc += pushnum stk.append(utils.bytearray_to_int(dat)) elif op[:3] == 'DUP': depth = int(op[3:]) # DUP POP POP Debug hint is_debug = 1 for i in range(depth): if compustate.pc + i < len(processed_code) and \ processed_code[compustate.pc + i][0] != 'POP': is_debug = 0 break if is_debug: stackargs = [stk.pop() for i in range(depth)] print(' '.join(map(repr, stackargs))) stk.extend(reversed(stackargs)) stk.append(stackargs[-1]) else: 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 == 'CREATE': value, mstart, msz = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart + msz): return OUT_OF_GAS data = ''.join(map(chr, mem[mstart: mstart + msz])) pblogger.log('SUB CONTRACT NEW', sender=msg.to, value=value, data=data.encode('hex')) create_msg = Message(msg.to, '', value, compustate.gas, data) addr, gas, code = create_contract(block, tx, create_msg) pblogger.log('SUB CONTRACT OUT', address=addr, code=code) if addr: stk.append(addr) compustate.gas = gas else: stk.append(0) compustate.gas = 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() new_memsize = max(meminstart + meminsz, memoutstart + memoutsz) if not mem_extend(mem, compustate, op, new_memsize): return OUT_OF_GAS if compustate.gas < gas: return out_of_gas_exception('subcall gas', gas, compustate, op) compustate.gas -= gas to = utils.encode_int(to) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') data = ''.join(map(chr, mem[meminstart: meminstart + meminsz])) pblogger.log('SUB CALL NEW', sender=msg.to, to=to, value=value, gas=gas, data=data.encode('hex')) call_msg = Message(msg.to, to, value, gas, data) result, gas, data = apply_msg_send(block, tx, call_msg) pblogger.log('SUB CALL OUT', result=result, data=data, length=len(data), expected=memoutsz) 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] elif op == 'RETURN': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0 + s1): return OUT_OF_GAS return mem[s0: s0 + s1] elif op == 'POST': gas, to, value, meminstart, meminsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, meminstart + meminsz): return OUT_OF_GAS if compustate.gas < gas: return out_of_gas_exception('subcall gas', gas, compustate, op) compustate.gas -= gas to = utils.encode_int(to) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') data = ''.join(map(chr, mem[meminstart: meminstart + meminsz])) pblogger.log('POST NEW', sender=msg.to, to=to, value=value, gas=gas, data=data.encode('hex')) post_msg = Message(msg.to, to, value, gas, data) block.postqueue.append(post_msg) elif op == 'CALL_STATELESS': gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() new_memsize = max(meminstart + meminsz, memoutstart + memoutsz) if not mem_extend(mem, compustate, op, new_memsize): return OUT_OF_GAS if compustate.gas < gas: return out_of_gas_exception('subcall gas', gas, compustate, op) compustate.gas -= gas to = utils.encode_int(to) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') data = ''.join(map(chr, mem[meminstart: meminstart + meminsz])) pblogger.log('SUB CALL NEW', sender=msg.to, to=to, value=value, gas=gas, data=data.encode('hex')) call_msg = Message(msg.to, msg.to, value, gas, data) result, gas, data = apply_msg(block, tx, call_msg, block.get_code(to)) pblogger.log('SUB CALL OUT', result=result, data=data, length=len(data), expected=memoutsz) 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] elif op == 'SUICIDE': to = utils.encode_int(stk.pop()) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') block.transfer_value(msg.to, to, block.get_balance(msg.to)) block.suicides.append(msg.to) return [] for a in stk: assert isinstance(a, (int, long))
def deserialize(cls, s): return big_endian_to_int(s)
def __hash__(self): return big_endian_to_int(self.hash)
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) while 1: 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=str(in_args), available=str(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'] = map(str, list(compustate.stack)) if log_vm_op_memory.is_active(): trace_data['memory'] = \ ''.join([chr(x).encode('hex') for x in compustate.memory]) if log_vm_op_storage.is_active(): trace_data['storage'] = ext.log_storage(msg.to) trace_data['gas'] = str(compustate.gas + fee) trace_data['pc'] = str(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 -= 10 * (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 = ''.join(map(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 '')) 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 '' 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.decode('hex'))) 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 = ''.join(map(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 else: gascost = opcodes.GSTORAGEADD if s1 else opcodes.GSTORAGEMOD if compustate.gas < gascost: return vm_exception('OUT OF GAS') compustate.gas -= max(gascost, 0) ext.add_refund(max( -gascost, 0)) # 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 if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') data = ''.join(map(chr, mem[mstart:mstart + msz])) ext.log(msg.to, topics, data) log_log.trace('LOG', to=msg.to, topics=topics, data=map(ord, data)) print('LOG', msg.to, topics, 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, '', 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') if compustate.gas < gas: return vm_exception('OUT OF GAS') if ext.get_balance(msg.to) >= value and msg.depth < 1024: compustate.gas -= gas to = utils.encode_int(to) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') cd = CallData(mem, meminstart, meminsz) call_msg = Message(msg.to, to, value, gas, cd, msg.depth + 1) result, gas, data = ext.call(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: 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') if compustate.gas < gas: return vm_exception('OUT OF GAS') if ext.get_balance(msg.to) >= value and msg.depth < 1024: compustate.gas -= gas to = utils.encode_int(to) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') cd = CallData(mem, meminstart, meminsz) call_msg = Message(msg.to, msg.to, value, gas, cd, msg.depth + 1) result, gas, data = ext.sendmsg(call_msg, ext.get_code(to)) 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: 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 = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') 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) return 1, compustate.gas, []
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([chr(x) for x in mem[s0:s0 + s1]]) stk.append(utils.big_endian_to_int(utils.sha3(data)))
def apply_op(block, tx, msg, code, compustate): op, in_args, out_args = get_op_data(code, compustate.pc) # empty stack error if in_args > len(compustate.stack): return [] # out of gas error fee = calcfee(block, tx, msg, compustate, op) if fee > compustate.gas: logger.debug("Out of gas %s need %s", compustate.gas, fee) logger.debug('%s %s', op, list(reversed(compustate.stack))) return OUT_OF_GAS stackargs = [] for i in range(in_args): stackargs.append(compustate.stack.pop()) if expensive_debug: import serpent if op[:4] == 'PUSH': start, n = compustate.pc + 1, int(op[4:]) logger.debug('%s %s ', op, utils.big_endian_to_int(code[start:start + n])) else: logger.debug('%s %s %s', op, ' '.join(map(str, stackargs)), serpent.decode_datalist(compustate.memory)) # Apply operation oldgas = compustate.gas oldpc = compustate.pc compustate.gas -= fee compustate.pc += 1 stk = compustate.stack mem = compustate.memory if op == 'STOP': return [] elif op == 'ADD': stk.append((stackargs[0] + stackargs[1]) % 2 ** 256) elif op == 'SUB': stk.append((stackargs[0] - stackargs[1]) % 2 ** 256) elif op == 'MUL': stk.append((stackargs[0] * stackargs[1]) % 2 ** 256) elif op == 'DIV': if stackargs[1] == 0: return [] stk.append(stackargs[0] / stackargs[1]) elif op == 'MOD': if stackargs[1] == 0: return [] stk.append(stackargs[0] % stackargs[1]) elif op == 'SDIV': if stackargs[1] == 0: return [] if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append((stackargs[0] / stackargs[1]) % 2 ** 256) elif op == 'SMOD': if stackargs[1] == 0: return [] if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append((stackargs[0] % stackargs[1]) % 2 ** 256) elif op == 'EXP': stk.append(pow(stackargs[0], stackargs[1], 2 ** 256)) elif op == 'NEG': stk.append(2 ** 256 - stackargs[0]) elif op == 'LT': stk.append(1 if stackargs[0] < stackargs[1] else 0) elif op == 'GT': stk.append(1 if stackargs[0] > stackargs[1] else 0) elif op == 'SLT': if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append(1 if stackargs[0] < stackargs[1] else 0) elif op == 'SGT': if stackargs[0] >= 2 ** 255: stackargs[0] -= 2 ** 256 if stackargs[1] >= 2 ** 255: stackargs[1] -= 2 ** 256 stk.append(1 if stackargs[0] > stackargs[1] else 0) elif op == 'EQ': stk.append(1 if stackargs[0] == stackargs[1] else 0) elif op == 'NOT': stk.append(0 if stackargs[0] else 1) elif op == 'AND': stk.append(stackargs[0] & stackargs[1]) elif op == 'OR': stk.append(stackargs[0] | stackargs[1]) elif op == 'XOR': stk.append(stackargs[0] ^ stackargs[1]) elif op == 'BYTE': if stackargs[0] >= 32: stk.append(0) else: stk.append((stackargs[1] / 256 ** stackargs[0]) % 256) elif op == 'SHA3': if len(mem) < ceil32(stackargs[0] + stackargs[1]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[1]) - len(mem))) data = ''.join(map(chr, mem[stackargs[0]:stackargs[0] + stackargs[1]])) stk.append(utils.big_endian_to_int(utils.sha3(data))) elif op == 'ADDRESS': stk.append(msg.to) elif op == 'BALANCE': stk.append(block.get_balance(msg.to)) elif op == 'ORIGIN': stk.append(tx.sender) elif op == 'CALLER': stk.append(utils.coerce_to_int(msg.sender)) elif op == 'CALLVALUE': stk.append(msg.value) elif op == 'CALLDATALOAD': if stackargs[0] >= len(msg.data): stk.append(0) else: dat = msg.data[stackargs[0]:stackargs[0] + 32] stk.append(utils.big_endian_to_int(dat + '\x00' * (32 - len(dat)))) elif op == 'CALLDATASIZE': stk.append(len(msg.data)) elif op == 'CALLDATACOPY': if len(mem) < ceil32(stackargs[1] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[1] + stackargs[2]) - len(mem))) for i in range(stackargs[2]): if stackargs[0] + i < len(msg.data): mem[stackargs[1] + i] = ord(msg.data[stackargs[0] + i]) else: mem[stackargs[1] + i] = 0 elif op == 'GASPRICE': stk.append(tx.gasprice) elif op == 'CODECOPY': if len(mem) < ceil32(stackargs[1] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[1] + stackargs[2]) - len(mem))) for i in range(stackargs[2]): if stackargs[0] + i < len(code): mem[stackargs[1] + i] = ord(code[stackargs[0] + i]) else: mem[stackargs[1] + i] = 0 elif op == 'PREVHASH': stk.append(utils.big_endian_to_int(block.prevhash)) elif op == 'COINBASE': stk.append(utils.big_endian_to_int(block.coinbase.decode('hex'))) elif op == 'TIMESTAMP': stk.append(block.timestamp) elif op == 'NUMBER': stk.append(block.number) elif op == 'DIFFICULTY': stk.append(block.difficulty) elif op == 'GASLIMIT': stk.append(block.gaslimit) elif op == 'POP': pass elif op == 'DUP': stk.append(stackargs[0]) stk.append(stackargs[0]) elif op == 'SWAP': stk.append(stackargs[0]) stk.append(stackargs[1]) elif op == 'MLOAD': if len(mem) < ceil32(stackargs[0] + 32): mem.extend([0] * (ceil32(stackargs[0] + 32) - len(mem))) data = ''.join(map(chr, mem[stackargs[0]:stackargs[0] + 32])) stk.append(utils.big_endian_to_int(data)) elif op == 'MSTORE': if len(mem) < ceil32(stackargs[0] + 32): mem.extend([0] * (ceil32(stackargs[0] + 32) - len(mem))) v = stackargs[1] for i in range(31, -1, -1): mem[stackargs[0] + i] = v % 256 v /= 256 elif op == 'MSTORE8': if len(mem) < ceil32(stackargs[0] + 1): mem.extend([0] * (ceil32(stackargs[0] + 1) - len(mem))) mem[stackargs[0]] = stackargs[1] % 256 elif op == 'SLOAD': stk.append(block.get_storage_data(msg.to, stackargs[0])) elif op == 'SSTORE': block.set_storage_data(msg.to, stackargs[0], stackargs[1]) elif op == 'JUMP': compustate.pc = stackargs[0] elif op == 'JUMPI': if stackargs[1]: compustate.pc = stackargs[0] elif op == 'PC': stk.append(compustate.pc) elif op == 'MSIZE': stk.append(len(mem)) elif op == 'GAS': stk.append(oldgas) elif op[:4] == 'PUSH': pushnum = int(op[4:]) compustate.pc = oldpc + 1 + pushnum dat = code[oldpc + 1: oldpc + 1 + pushnum] stk.append(utils.big_endian_to_int(dat)) elif op == 'CREATE': if len(mem) < ceil32(stackargs[2] + stackargs[3]): mem.extend([0] * (ceil32(stackargs[2] + stackargs[3]) - len(mem))) gas = stackargs[0] value = stackargs[1] data = ''.join(map(chr, mem[stackargs[2]:stackargs[2] + stackargs[3]])) logger.debug("Sub-contract: %s %s %s %s ", msg.to, value, gas, data) addr, gas, code = create_contract( block, tx, Message(msg.to, '', value, gas, data)) logger.debug("Output of contract creation: %s %s ", addr, code) if addr: stk.append(utils.coerce_to_int(addr)) else: stk.append(0) elif op == 'CALL': if len(mem) < ceil32(stackargs[3] + stackargs[4]): mem.extend([0] * (ceil32(stackargs[3] + stackargs[4]) - len(mem))) if len(mem) < ceil32(stackargs[5] + stackargs[6]): mem.extend([0] * (ceil32(stackargs[5] + stackargs[6]) - len(mem))) gas = stackargs[0] to = utils.encode_int(stackargs[1]) to = (('\x00' * (32 - len(to))) + to)[12:] value = stackargs[2] data = ''.join(map(chr, mem[stackargs[3]:stackargs[3] + stackargs[4]])) logger.debug( "Sub-call: %s %s %s %s %s ", utils.coerce_addr_to_hex(msg.to), utils.coerce_addr_to_hex(to), value, gas, data) result, gas, data = apply_msg( block, tx, Message(msg.to, to, value, gas, data)) logger.debug( "Output of sub-call: %s %s length %s expected %s", result, data, len(data), stackargs[6]) for i in range(stackargs[6]): mem[stackargs[5] + i] = 0 if result == 0: stk.append(0) else: stk.append(1) compustate.gas += gas for i in range(len(data)): mem[stackargs[5] + i] = data[i] elif op == 'RETURN': if len(mem) < ceil32(stackargs[0] + stackargs[1]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[1]) - len(mem))) return mem[stackargs[0]:stackargs[0] + stackargs[1]] elif op == 'SUICIDE': to = utils.encode_int(stackargs[0]) to = (('\x00' * (32 - len(to))) + to)[12:] block.delta_balance(to, block.get_balance(msg.to)) block.state.delete(msg.to) return []
def OP_COINBASE(): stk.append(utils.big_endian_to_int(block.coinbase.decode('hex')))
def apply_op(block, tx, msg, code, compustate): op, in_args, out_args, mem_grabs, base_gas = opdata = get_op_data( code, compustate.pc) # empty stack error if in_args > len(compustate.stack): return [] # out of gas error fee = calcfee(block, tx, msg, compustate, opdata) if fee > compustate.gas: pblogger.log('OUT OF GAS', needed=fee, available=compustate.gas, op=op, stack=list(reversed(compustate.stack))) return OUT_OF_GAS stackargs = [] for i in range(in_args): stackargs.append(compustate.stack.pop()) if pblogger.log_op: log_args = dict(pc=compustate.pc, op=op, stackargs=stackargs, gas=compustate.gas) if op[:4] == 'PUSH': ind = compustate.pc + 1 log_args['value'] = utils.big_endian_to_int(code[ind:ind + int(op[4:])]) elif op == 'CALLDATACOPY': log_args['data'] = msg.data.encode('hex') elif op == 'SSTORE': log_args['key'] = stackargs[0] log_args['value'] = stackargs[1] pblogger.log('OP', **log_args) if pblogger.log_memory: for i in range(0, len(compustate.memory), 16): memblk = compustate.memory[i:i + 16] memline = ' '.join([chr(x).encode('hex') for x in memblk]) pblogger.log('MEM', mem=memline) # Apply operation oldpc = compustate.pc compustate.gas -= fee compustate.pc += 1 stk = compustate.stack mem = compustate.memory if op == 'STOP' or op == 'INVALID': return [] elif op == 'ADD': stk.append((stackargs[0] + stackargs[1]) % 2**256) elif op == 'SUB': stk.append((stackargs[0] - stackargs[1]) % 2**256) elif op == 'MUL': stk.append((stackargs[0] * stackargs[1]) % 2**256) elif op == 'DIV': stk.append(0 if stackargs[1] == 0 else stackargs[0] / stackargs[1]) elif op == 'MOD': stk.append(0 if stackargs[1] == 0 else stackargs[0] % stackargs[1]) elif op == 'SDIV': if stackargs[0] >= 2**255: stackargs[0] -= 2**256 if stackargs[1] >= 2**255: stackargs[1] -= 2**256 stk.append(0 if stackargs[1] == 0 else (stackargs[0] / stackargs[1]) % 2**256) elif op == 'SMOD': if stackargs[0] >= 2**255: stackargs[0] -= 2**256 if stackargs[1] >= 2**255: stackargs[1] -= 2**256 stk.append(0 if stackargs[1] == 0 else (stackargs[0] % stackargs[1]) % 2**256) elif op == 'EXP': stk.append(pow(stackargs[0], stackargs[1], 2**256)) elif op == 'NEG': stk.append(-stackargs[0] % 2**256) elif op == 'LT': stk.append(1 if stackargs[0] < stackargs[1] else 0) elif op == 'GT': stk.append(1 if stackargs[0] > stackargs[1] else 0) elif op == 'SLT': if stackargs[0] >= 2**255: stackargs[0] -= 2**256 if stackargs[1] >= 2**255: stackargs[1] -= 2**256 stk.append(1 if stackargs[0] < stackargs[1] else 0) elif op == 'SGT': if stackargs[0] >= 2**255: stackargs[0] -= 2**256 if stackargs[1] >= 2**255: stackargs[1] -= 2**256 stk.append(1 if stackargs[0] > stackargs[1] else 0) elif op == 'EQ': stk.append(1 if stackargs[0] == stackargs[1] else 0) elif op == 'NOT': stk.append(0 if stackargs[0] else 1) elif op == 'AND': stk.append(stackargs[0] & stackargs[1]) elif op == 'OR': stk.append(stackargs[0] | stackargs[1]) elif op == 'XOR': stk.append(stackargs[0] ^ stackargs[1]) elif op == 'BYTE': if stackargs[0] >= 32: stk.append(0) else: stk.append((stackargs[1] / 256**(31 - stackargs[0])) % 256) elif op == 'ADDMOD': stk.append((stackargs[2] + stackargs[1]) % stackargs[0]) elif op == 'MULMOD': stk.append((stackargs[2] * stackargs[1]) % stackargs[0]) elif op == 'SHA3': if len(mem) < ceil32(stackargs[0] + stackargs[1]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[1]) - len(mem))) data = ''.join(map(chr, mem[stackargs[0]:stackargs[0] + stackargs[1]])) stk.append(utils.big_endian_to_int(utils.sha3(data))) elif op == 'ADDRESS': stk.append(utils.coerce_to_int(msg.to)) elif op == 'BALANCE': stk.append(block.get_balance(utils.coerce_addr_to_hex(stackargs[0]))) elif op == 'ORIGIN': stk.append(utils.coerce_to_int(tx.sender)) elif op == 'CALLER': stk.append(utils.coerce_to_int(msg.sender)) elif op == 'CALLVALUE': stk.append(msg.value) elif op == 'CALLDATALOAD': if stackargs[0] >= len(msg.data): stk.append(0) else: dat = msg.data[stackargs[0]:stackargs[0] + 32] stk.append(utils.big_endian_to_int(dat + '\x00' * (32 - len(dat)))) elif op == 'CALLDATASIZE': stk.append(len(msg.data)) elif op == 'CALLDATACOPY': if len(mem) < ceil32(stackargs[0] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[2]) - len(mem))) for i in range(stackargs[2]): if stackargs[1] + i < len(msg.data): mem[stackargs[0] + i] = ord(msg.data[stackargs[1] + i]) else: mem[stackargs[0] + i] = 0 elif op == 'GASPRICE': stk.append(tx.gasprice) elif op == 'CODECOPY': if len(mem) < ceil32(stackargs[0] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[2]) - len(mem))) for i in range(stackargs[2]): if stackargs[1] + i < len(code): mem[stackargs[0] + i] = ord(code[stackargs[1] + i]) else: mem[stackargs[0] + i] = 0 elif op == 'PREVHASH': stk.append(utils.big_endian_to_int(block.prevhash)) elif op == 'COINBASE': stk.append(utils.big_endian_to_int(block.coinbase.decode('hex'))) elif op == 'TIMESTAMP': stk.append(block.timestamp) elif op == 'NUMBER': stk.append(block.number) elif op == 'DIFFICULTY': stk.append(block.difficulty) elif op == 'GASLIMIT': stk.append(block.gas_limit) elif op == 'POP': pass elif op == 'DUP': # DUP POP POP Debug hint if get_op_data(code, oldpc + 1)[0] == 'POP' and \ get_op_data(code, oldpc + 2)[0] == 'POP': compustate.pc = oldpc + 3 else: stk.append(stackargs[0]) stk.append(stackargs[0]) elif op == 'SWAP': stk.append(stackargs[0]) stk.append(stackargs[1]) elif op == 'MLOAD': if len(mem) < ceil32(stackargs[0] + 32): mem.extend([0] * (ceil32(stackargs[0] + 32) - len(mem))) data = ''.join(map(chr, mem[stackargs[0]:stackargs[0] + 32])) stk.append(utils.big_endian_to_int(data)) elif op == 'MSTORE': if len(mem) < ceil32(stackargs[0] + 32): mem.extend([0] * (ceil32(stackargs[0] + 32) - len(mem))) v = stackargs[1] for i in range(31, -1, -1): mem[stackargs[0] + i] = v % 256 v /= 256 elif op == 'MSTORE8': if len(mem) < ceil32(stackargs[0] + 1): mem.extend([0] * (ceil32(stackargs[0] + 1) - len(mem))) mem[stackargs[0]] = stackargs[1] % 256 elif op == 'SLOAD': stk.append(block.get_storage_data(msg.to, stackargs[0])) elif op == 'SSTORE': block.set_storage_data(msg.to, stackargs[0], stackargs[1]) elif op == 'JUMP': compustate.pc = stackargs[0] elif op == 'JUMPI': if stackargs[1]: compustate.pc = stackargs[0] elif op == 'PC': stk.append(compustate.pc) 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 = oldpc + 1 + pushnum dat = code[oldpc + 1:oldpc + 1 + pushnum] stk.append(utils.big_endian_to_int(dat)) elif op[:4] == 'DUP': dupnum = int(op[4:]) - 1 stk.extend(reversed(stackargs)) stk.append(stackargs[dupnum]) elif op[:4] == 'SWAP': swapnum = int(op[4:]) stk.append(stackargs[0]) stk.extend(reversed(stackargs[1:-1])) stk.append(stackargs[-1]) elif op == 'CREATE': if len(mem) < ceil32(stackargs[1] + stackargs[2]): mem.extend([0] * (ceil32(stackargs[1] + stackargs[2]) - len(mem))) value = stackargs[0] data = ''.join(map(chr, mem[stackargs[1]:stackargs[1] + stackargs[2]])) pblogger.log('SUB CONTRACT NEW', sender=msg.to, value=value, data=data.encode('hex')) create_msg = Message(msg.to, '', value, compustate.gas, data) addr, gas, code = create_contract(block, tx, create_msg) pblogger.log('SUB CONTRACT OUT', address=addr, code=code) if addr: stk.append(addr) compustate.gas = gas else: stk.append(0) compustate.gas = 0 elif op == 'CALL': if len(mem) < ceil32(stackargs[3] + stackargs[4]): mem.extend([0] * (ceil32(stackargs[3] + stackargs[4]) - len(mem))) if len(mem) < ceil32(stackargs[5] + stackargs[6]): mem.extend([0] * (ceil32(stackargs[5] + stackargs[6]) - len(mem))) gas = stackargs[0] to = utils.encode_int(stackargs[1]) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') value = stackargs[2] data = ''.join(map(chr, mem[stackargs[3]:stackargs[3] + stackargs[4]])) pblogger.log('SUB CALL NEW', sender=msg.to, to=to, value=value, gas=gas, data=data.encode('hex')) call_msg = Message(msg.to, to, value, gas, data) result, gas, data = apply_msg_send(block, tx, call_msg) pblogger.log('SUB CALL OUT', result=result, data=data, length=len(data), expected=stackargs[6]) if result == 0: stk.append(0) else: stk.append(1) compustate.gas += gas for i in range(min(len(data), stackargs[6])): mem[stackargs[5] + i] = data[i] elif op == 'RETURN': if len(mem) < ceil32(stackargs[0] + stackargs[1]): mem.extend([0] * (ceil32(stackargs[0] + stackargs[1]) - len(mem))) return mem[stackargs[0]:stackargs[0] + stackargs[1]] elif op == 'POST': if len(mem) < ceil32(stackargs[3] + stackargs[4]): mem.extend([0] * (ceil32(stackargs[3] + stackargs[4]) - len(mem))) gas = stackargs[0] to = utils.encode_int(stackargs[1]) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') value = stackargs[2] data = ''.join(map(chr, mem[stackargs[3]:stackargs[3] + stackargs[4]])) pblogger.log('POST NEW', sender=msg.to, to=to, value=value, gas=gas, data=data.encode('hex')) post_msg = Message(msg.to, to, vaue, gas, data) block.postqueue.append(post_msg) elif op == 'SUICIDE': to = utils.encode_int(stackargs[0]) to = (('\x00' * (32 - len(to))) + to)[12:].encode('hex') block.transfer_value(msg.to, to, block.get_balance(msg.to)) block.suicides.append(msg.to) return [] for a in stk: assert isinstance(a, (int, long))