def sender(self): if not self._sender: # Determine sender if self.r == 0 and self.s == 0: self._sender = null_address else: if self.v in (27, 28): vee = self.v sighash = utils.sha3(rlp.encode(self, UnsignedTransaction)) elif self.v >= 37: vee = self.v - self.network_id * 2 - 8 assert vee in (27, 28) rlpdata = rlp.encode( rlp.infer_sedes(self).serialize(self)[:-3] + [self.network_id, '', '']) sighash = utils.sha3(rlpdata) else: raise InvalidTransaction("Invalid V value") if self.r >= secpk1n or self.s >= secpk1n or self.r == 0 or self.s == 0: raise InvalidTransaction("Invalid signature values!") pub = ecrecover_to_pub(sighash, vee, self.r, self.s) if pub == b'\x00' * 64: raise InvalidTransaction( "Invalid signature (zero privkey cannot sign)") self._sender = utils.sha3(pub)[-20:] return self._sender
def get_parent(self, val): origval = val for i in range(RANDAO_SAVE_INTERVAL): if val in self.medstate: o = self.get( self.medstate.index(val) * RANDAO_SAVE_INTERVAL - i - 1) assert utils.sha3(o) == origval return o val = utils.sha3(val) raise Exception("Randao parent not found")
def test_block_18315_changes(): pre = {} toadd = [ [ '0x0000000000000000000000000000000000000000000000000000000000000000', '0xf9e88bc2b3203e764fe67b4d0f4171b7756117c8' ], [ '0x0000000000000000000000000000000000000000000000000000000000000001', '0x' ], [ '0x0000000000000000000000000000000000000000000000000000000000000002', '0x' ], ] db = RefcountDB(EphemDB()) db.logging = True NODES = 60 t1 = pruning_trie.Trie(db) t2 = pruning_trie.Trie(db) db.ttl = NODES * 2 c = 0 for k, v in pre.items(): triekey = utils.sha3(utils.zpad(k[2:].decode('hex'), 32)) t1.update(triekey, rlp.encode(v[2:].decode('hex'))) t2.update(triekey, rlp.encode(v[2:].decode('hex'))) db.commit_refcount_changes(c) db.cleanup(c) c += 1 sys.stderr.write('##############################\n') print(utils.encode_hex(t1.root_hash)) print(t1.to_dict()) for k, v in toadd: sys.stderr.write('kv: %s %s\n' % (k, v)) triekey = utils.sha3(utils.zpad(utils.decode_hex(k[2:]), 32)) if v == '0x': t1.delete(triekey) else: t1.update(triekey, rlp.encode(utils.decode_hex(v[2:]))) db.commit_refcount_changes(c) db.cleanup(c) c += 1 t1.clear_all() db.commit_refcount_changes(c) for i in range(db.ttl + 1): db.cleanup(c) c += 1 t3 = pruning_trie.Trie(db) t3.root_hash = t2.root_hash print(t3.to_dict())
def test_string_logging(): c = tester.Chain() x = c.contract(string_logging_code, language='serpent') o = [] c.head_state.log_listeners.append( lambda f: o.append(x.translator.listen(f))) x.moo() assert o == [{ "_event_type": b"foo", "x": b"bob", "__hash_x": utils.sha3(b"bob"), "y": b"cow", "__hash_y": utils.sha3(b"cow"), "z": b"dog", "__hash_z": utils.sha3(b"dog"), }]
def bloom_bits(val): h = utils.sha3(val) return [ bits_in_number(1 << ((safe_ord(h[i + 1]) + (safe_ord(h[i]) << 8)) & 2047)) for i in range(0, BUCKETS_PER_VAL * 2, 2) ]
def make_casper_genesis(alloc, epoch_length, withdrawal_delay, base_interest_factor, base_penalty_factor): # The Casper-specific config declaration casper_config = copy.deepcopy(config.default_config) casper_config['HOMESTEAD_FORK_BLKNUM'] = 0 casper_config['ANTI_DOS_FORK_BLKNUM'] = 0 casper_config['CLEARING_FORK_BLKNUM'] = 0 casper_config['CONSENSUS_STRATEGY'] = 'hybrid_casper' casper_config['NULL_SENDER'] = utils.sha3('NULL_SENDER') casper_config['EPOCH_LENGTH'] = epoch_length casper_config['WITHDRAWAL_DELAY'] = withdrawal_delay casper_config['OWNER'] = a0 casper_config['BASE_INTEREST_FACTOR'] = base_interest_factor casper_config['BASE_PENALTY_FACTOR'] = base_penalty_factor # Get initialization txs init_txs, casper_address = mk_initializers(casper_config, casper_config['NULL_SENDER']) casper_config['CASPER_ADDRESS'] = casper_address # Create state and apply required state_transitions for initializing Casper state = genesis_helpers.mk_basic_state( alloc, None, env=config.Env(config=casper_config)) state.gas_limit = 10**8 for tx in init_txs: state.set_balance(utils.privtoaddr(casper_config['NULL_SENDER']), 15**18) success, output = apply_transaction(state, tx) assert success state.gas_used = 0 state.set_balance(utils.privtoaddr(casper_config['NULL_SENDER']), 0) consensus.initialize(state) state.commit() return state
def proc_ecrecover(ext, msg): # print('ecrecover proc', msg.gas) OP_GAS = opcodes.GECRECOVER gas_cost = OP_GAS if msg.gas < gas_cost: return 0, 0, [] message_hash_bytes = [0] * 32 msg.data.extract_copy(message_hash_bytes, 0, 0, 32) message_hash = b''.join(map(ascii_chr, message_hash_bytes)) # TODO: This conversion isn't really necessary. # TODO: Invesitage if the check below is really needed. v = msg.data.extract32(32) r = msg.data.extract32(64) s = msg.data.extract32(96) if r >= secp256k1n or s >= secp256k1n or v < 27 or v > 28: return 1, msg.gas - opcodes.GECRECOVER, [] try: pub = utils.ecrecover_to_pub(message_hash, v, r, s) except Exception as e: return 1, msg.gas - gas_cost, [] o = [0] * 12 + [safe_ord(x) for x in utils.sha3(pub)[-20:]] return 1, msg.gas - gas_cost, o
def make_head_candidate(chain, txqueue=None, parent=None, timestamp=None, coinbase=b'\x35' * 20, extra_data='moo ha ha says the laughing cow.', min_gasprice=0): log.debug('Creating head candidate') if parent is None: temp_state = State.from_snapshot( chain.state.to_snapshot( root_only=True), chain.env) else: temp_state = chain.mk_poststate_of_blockhash(parent.hash) cs = get_consensus_strategy(chain.env.config) # Initialize a block with the given parent and variables blk = mk_block_from_prevstate( chain, temp_state, timestamp, coinbase, extra_data) # Find and set the uncles blk.uncles = cs.get_uncles(chain, temp_state) blk.header.uncles_hash = sha3(rlp.encode(blk.uncles)) # Call the initialize state transition function cs.initialize(temp_state, blk) # Add transactions add_transactions(temp_state, blk, txqueue, min_gasprice) # Call the finalize state transition function cs.finalize(temp_state, blk) # Set state root, receipt root, etc set_execution_results(temp_state, blk) log.debug('Created head candidate successfully') return blk, temp_state
def test_ecrecover(): c = tester.Chain() x = c.contract(ecrecover_code, language='serpent') priv = utils.sha3('some big long brainwallet password') pub = bitcoin.privtopub(priv) msghash = utils.sha3('the quick brown fox jumps over the lazy dog') V, R, S = utils.ecsign(msghash, priv) assert bitcoin.ecdsa_raw_verify(msghash, (V, R, S), pub) addr = utils.big_endian_to_int( utils.sha3(bitcoin.encode_pubkey(pub, 'bin')[1:])[12:]) assert utils.big_endian_to_int(utils.privtoaddr(priv)) == addr result = x.test_ecrecover(utils.big_endian_to_int(msghash), V, R, S) assert result == addr
def get_root_hash(self): if self.transient: return self.transient_root_hash if self.root_node == BLANK_NODE: return BLANK_ROOT assert isinstance(self.root_node, list) val = rlp_encode(self.root_node) key = utils.sha3(val) self.spv_grabbing(self.root_node) return key
def _encode_node(self, node, is_root=False): if node == BLANK_NODE: return BLANK_NODE # assert isinstance(node, list) rlpnode = rlp_encode(node) if len(rlpnode) < 32 and not is_root: return node hashkey = utils.sha3(rlpnode) self.db.inc_refcount(hashkey, rlpnode) return hashkey
def _encode_node(self, node, put_in_db=True): if node == BLANK_NODE: return BLANK_NODE # assert isinstance(node, list) rlpnode = rlp_encode(node) if len(rlpnode) < 32: return node hashkey = utils.sha3(rlpnode) if put_in_db: self.db.put(hashkey, str_to_bytes(rlpnode)) return hashkey
def mk_prepare(validator_index, epoch, ancestry_hash, source_epoch, source_ancestry_hash, key): sighash = utils.sha3( rlp.encode([ validator_index, epoch, ancestry_hash, source_epoch, source_ancestry_hash ])) v, r, s = utils.ecdsa_raw_sign(sighash, key) sig = utils.encode_int32(v) + utils.encode_int32(r) + utils.encode_int32(s) return rlp.encode([ validator_index, epoch, ancestry_hash, source_epoch, source_ancestry_hash, sig ])
def sign(self, key, network_id=None): """Sign this transaction with a private key. A potentially already existing signature would be overridden. """ if network_id is None: rawhash = utils.sha3(rlp.encode(self, UnsignedTransaction)) else: assert 1 <= network_id < 2**63 - 18 rlpdata = rlp.encode( rlp.infer_sedes(self).serialize(self)[:-3] + [network_id, b'', b'']) rawhash = utils.sha3(rlpdata) key = normalize_key(key) self.v, self.r, self.s = ecsign(rawhash, key) if network_id is not None: self.v += 8 + network_id * 2 self._sender = utils.privtoaddr(key) return self
def test_block_18503_changes(): pre = {'0x0c': '0x29d33c02a200937995e632c4597b4dca8e503978'} toadd = [ ['0x', '0x09'], ] db = RefcountDB(EphemDB()) db.logging = True NODES = 60 t1 = pruning_trie.Trie(db) t2 = pruning_trie.Trie(db) db.ttl = NODES * 2 c = 0 for k, v in pre.items(): triekey = utils.sha3(utils.zpad(utils.decode_hex(k[2:]), 32)) t1.update(triekey, rlp.encode(utils.decode_hex(v[2:]))) t2.update(triekey, rlp.encode(utils.decode_hex(v[2:]))) db.commit_refcount_changes(c) db.cleanup(c) c += 1 print(utils.encode_hex(t1.root_hash)) for k, v in toadd: sys.stderr.write('kv: %s %s\n' % (k, v)) triekey = utils.sha3(utils.zpad(utils.decode_hex(k[2:]), 32)) if v == '0x': t1.delete(triekey) else: t1.update(triekey, rlp.encode(utils.decode_hex(v[2:]))) db.commit_refcount_changes(c) db.cleanup(c) c += 1 t1.clear_all() db.commit_refcount_changes(c) for i in range(db.ttl + 1): db.cleanup(c) c += 1 t3 = pruning_trie.Trie(db) t3.root_hash = t2.root_hash print(t3.to_dict())
def get_cache(block_number): import sha3 while len(cache_seeds) <= block_number // EPOCH_LENGTH: cache_seeds.append(utils.sha3(cache_seeds[-1])) seed = cache_seeds[block_number // EPOCH_LENGTH] if seed in cache_by_seed: c = cache_by_seed.pop(seed) # pop and append at end cache_by_seed[seed] = c return c c = mkcache(block_number) cache_by_seed[seed] = c if len(cache_by_seed) > cache_by_seed.max_items: # remove last recently accessed cache_by_seed.pop(cache_by_seed.keys()[0]) return c
def verify_spv_proof(root, key, proof): proof.push(VERIFYING, proof) t = Trie(db.EphemDB()) for i, node in enumerate(proof): R = rlp_encode(node) H = utils.sha3(R) t.db.put(H, R) try: t.root_hash = root t.get(key) proof.pop() return True except Exception as e: print(e) proof.pop() return False
def _delete_node_storage(self, node, is_root=False): """delete storage :param node: node in form of list, or BLANK_NODE """ if node == BLANK_NODE: return # assert isinstance(node, list) encoded = rlp_encode(node) if len(encoded) < 32 and not is_root: return """ ===== FIXME ==== in the current trie implementation two nodes can share identical subtrees thus we can not safely delete nodes for now """ hashkey = utils.sha3(encoded) self.db.dec_refcount(hashkey)
def validate_uncles(state, block): """Validate the uncles of this block.""" # Make sure hash matches up if utils.sha3(rlp.encode(block.uncles)) != block.header.uncles_hash: raise VerificationFailed("Uncle hash mismatch") # Enforce maximum number of uncles if len(block.uncles) > state.config['MAX_UNCLES']: raise VerificationFailed("Too many uncles") # Uncle must have lower block number than blockj for uncle in block.uncles: if uncle.number >= block.header.number: raise VerificationFailed("Uncle number too high") # Check uncle validity MAX_UNCLE_DEPTH = state.config['MAX_UNCLE_DEPTH'] ancestor_chain = [block.header] + \ [a for a in state.prev_headers[:MAX_UNCLE_DEPTH + 1] if a] # Uncles of this block cannot be direct ancestors and cannot also # be uncles included 1-6 blocks ago ineligible = [b.hash for b in ancestor_chain] for blknum, uncles in state.recent_uncles.items(): if state.block_number > int( blknum) >= state.block_number - MAX_UNCLE_DEPTH: ineligible.extend([u for u in uncles]) eligible_ancestor_hashes = [x.hash for x in ancestor_chain[2:]] for uncle in block.uncles: if uncle.prevhash not in eligible_ancestor_hashes: raise VerificationFailed("Uncle does not have a valid ancestor") parent = [x for x in ancestor_chain if x.hash == uncle.prevhash][0] if uncle.difficulty != calc_difficulty( parent, uncle.timestamp, config=state.config): raise VerificationFailed("Difficulty mismatch") if uncle.number != parent.number + 1: raise VerificationFailed("Number mismatch") if uncle.timestamp < parent.timestamp: raise VerificationFailed("Timestamp mismatch") if uncle.hash in ineligible: raise VerificationFailed("Duplicate uncle") if uncle.gas_used > uncle.gas_limit: raise VerificationFailed("Uncle used too much gas") if not check_pow(state, uncle): raise VerificationFailed('uncle pow mismatch') ineligible.append(uncle.hash) return True
def vm_trace(ext, msg, compustate, opcode, pushcache, tracer=log_vm_op): """ This diverges from normal logging, as we use the logging namespace only to decide which features get logged in 'bible.vm.op' i.e. tracing can not be activated by activating a sub like 'bible.vm.op.stack' """ op, in_args, out_args, fee = opcodes.opcodes[opcode] trace_data = {} trace_data['stack'] = list(map(to_string, list(compustate.prev_stack))) if compustate.prev_prev_op in ('MLOAD', 'MSTORE', 'MSTORE8', 'SHA3', 'CALL', 'CALLCODE', 'CREATE', 'CALLDATACOPY', 'CODECOPY', 'EXTCODECOPY'): if len(compustate.prev_memory) < 4096: trace_data['memory'] = \ ''.join([encode_hex(ascii_chr(x)) for x in compustate.prev_memory]) else: trace_data['sha3memory'] = \ encode_hex(utils.sha3(b''.join([ascii_chr(x) for x in compustate.prev_memory]))) if compustate.prev_prev_op in ('SSTORE',) or compustate.steps == 0: trace_data['storage'] = ext.log_storage(msg.to) trace_data['gas'] = to_string(compustate.prev_gas) trace_data['gas_cost'] = to_string(compustate.prev_gas - compustate.gas) trace_data['fee'] = fee trace_data['inst'] = opcode trace_data['pc'] = to_string(compustate.prev_pc) if compustate.steps == 0: trace_data['depth'] = msg.depth trace_data['address'] = msg.to trace_data['steps'] = compustate.steps trace_data['depth'] = msg.depth if op[:4] == 'PUSH': print(repr(pushcache)) trace_data['pushvalue'] = pushcache[compustate.prev_pc] tracer.trace('vm', op=op, **trace_data) compustate.steps += 1 compustate.prev_prev_op = op
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_type(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_type(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 verify_independent_transaction_spv_proof(db, proof): _, prevheader, header, index, nodes = rlp.decode(proof) index = utils.decode_int(index) pb = blocks.Block.deserialize_header(prevheader) b = blocks.Block.init_from_header(db, header) b.set_proof_mode(blocks.VERIFYING, nodes) if index != 0: pre_med, pre_gas, _, _ = b.get_receipt(index - 1) else: pre_med, pre_gas = pb['state_root'], '' if utils.sha3(rlp.encode(prevheader)) != b.prevhash: return False b.state_root = pre_med b.gas_used = utils.decode_int(pre_gas) tx = b.get_transaction(index) post_med, post_gas, bloom, logs = b.get_receipt(index) tx = transactions.Transaction.create(tx) o = verify_transaction_spv_proof(b, tx, nodes) if b.state_root == post_med: if b.gas_used == utils.decode_int(post_gas): if [x.serialize() for x in b.logs] == logs: if b.mk_log_bloom() == bloom: return o return False
def hash(self): """The binary block hash""" return utils.sha3(rlp.encode(self))
def vm_execute(ext, msg, code): # precompute trace flag # if we trace vm, we're in slow mode anyway trace_vm = log_vm_op.is_active('trace') compustate = Compustate(gas=msg.gas) stk = compustate.stack mem = compustate.memory if code in code_cache: processed_code = code_cache[code] else: processed_code = preprocess_code(code) code_cache[code] = processed_code # print(processed_code.keys(), code) codelen = len(code) s = time.time() steps = 0 _prevop = None # for trace only while compustate.pc in processed_code: ops, minstack, maxstack, totgas, nextpos = processed_code[ compustate.pc] if len(compustate.stack) < minstack: return vm_exception('INSUFFICIENT STACK') if len(compustate.stack) > maxstack: return vm_exception('STACK SIZE LIMIT EXCEEDED') if totgas > compustate.gas: return vm_exception('OUT OF GAS %d %d' % (totgas, compustate.gas)) jumped = False compustate.gas -= totgas compustate.pc = nextpos # Invalid operation; can only come at the end of a chunk if ops[-1][0] == 'INVALID': return vm_exception('INVALID OP', opcode=ops[-1][1]) for op, opcode, pushval in ops: if trace_vm: """ This diverges from normal logging, as we use the logging namespace only to decide which features get logged in 'bible.vm.op' i.e. tracing can not be activated by activating a sub like 'bible.vm.op.stack' """ trace_data = {} trace_data['stack'] = list( map(to_string, list(compustate.stack))) if _prevop in ('MLOAD', 'MSTORE', 'MSTORE8', 'SHA3', 'CALL', 'CALLCODE', 'CREATE', 'CALLDATACOPY', 'CODECOPY', 'EXTCODECOPY'): if len(compustate.memory) < 1024: trace_data['memory'] = \ ''.join([encode_hex(ascii_chr(x)) for x in compustate.memory]) else: trace_data['sha3memory'] = \ encode_hex(utils.sha3(b''.join([ascii_chr(x) for x in compustate.memory]))) if _prevop in ('SSTORE', ) or steps == 0: trace_data['storage'] = ext.log_storage(msg.to) trace_data['gas'] = to_string(compustate.gas + totgas) trace_data['inst'] = opcode trace_data['pc'] = to_string(compustate.pc - 1) if steps == 0: trace_data['depth'] = msg.depth trace_data['address'] = msg.to trace_data['steps'] = steps trace_data['depth'] = msg.depth if op[:4] == 'PUSH': trace_data['pushvalue'] = pushval log_vm_op.trace('vm', op=op, **trace_data) steps += 1 _prevop = op # Valid operations # Pushes first because they are very frequent if 0x60 <= opcode <= 0x7f: # compustate.pc += opcode - 0x5f # Move 1 byte forward for # 0x60, up to 32 bytes for 0x7f stk.append(pushval) elif opcode < 0x10: if op == 'STOP': return peaceful_exit('STOP', compustate.gas, []) elif op == 'ADD': stk.append((stk.pop() + stk.pop()) & TT256M1) elif op == 'SUB': stk.append((stk.pop() - stk.pop()) & TT256M1) elif op == 'MUL': stk.append((stk.pop() * stk.pop()) & TT256M1) elif op == 'DIV': s0, s1 = stk.pop(), stk.pop() stk.append(0 if s1 == 0 else s0 // s1) elif op == 'MOD': s0, s1 = stk.pop(), stk.pop() stk.append(0 if s1 == 0 else s0 % s1) elif op == 'SDIV': s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(0 if s1 == 0 else (abs(s0) // abs(s1) * (-1 if s0 * s1 < 0 else 1)) & TT256M1) elif op == 'SMOD': s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(0 if s1 == 0 else (abs(s0) % abs(s1) * (-1 if s0 < 0 else 1)) & TT256M1) elif op == 'ADDMOD': s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() stk.append((s0 + s1) % s2 if s2 else 0) elif op == 'MULMOD': s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() stk.append((s0 * s1) % s2 if s2 else 0) elif op == 'EXP': base, exponent = stk.pop(), stk.pop() # fee for exponent is dependent on its bytes # calc n bytes to represent exponent nbytes = len(utils.encode_int(exponent)) expfee = nbytes * opcodes.GEXPONENTBYTE if ext.post_clearing_hardfork(): expfee += opcodes.EXP_SUPPLEMENTAL_GAS * nbytes if compustate.gas < expfee: compustate.gas = 0 return vm_exception('OOG EXPONENT') compustate.gas -= expfee stk.append(pow(base, exponent, TT256)) elif op == 'SIGNEXTEND': s0, s1 = stk.pop(), stk.pop() if s0 <= 31: testbit = s0 * 8 + 7 if s1 & (1 << testbit): stk.append(s1 | (TT256 - (1 << testbit))) else: stk.append(s1 & ((1 << testbit) - 1)) else: stk.append(s1) elif opcode < 0x20: if op == 'LT': stk.append(1 if stk.pop() < stk.pop() else 0) elif op == 'GT': stk.append(1 if stk.pop() > stk.pop() else 0) elif op == 'SLT': s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(1 if s0 < s1 else 0) elif op == 'SGT': s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(1 if s0 > s1 else 0) elif op == 'EQ': stk.append(1 if stk.pop() == stk.pop() else 0) elif op == 'ISZERO': stk.append(0 if stk.pop() else 1) elif op == 'AND': stk.append(stk.pop() & stk.pop()) elif op == 'OR': stk.append(stk.pop() | stk.pop()) elif op == 'XOR': stk.append(stk.pop() ^ stk.pop()) elif op == 'NOT': stk.append(TT256M1 - stk.pop()) elif op == 'BYTE': s0, s1 = stk.pop(), stk.pop() if s0 >= 32: stk.append(0) else: stk.append((s1 // 256**(31 - s0)) % 256) elif opcode < 0x40: if op == 'SHA3': s0, s1 = stk.pop(), stk.pop() compustate.gas -= opcodes.GSHA3WORD * \ (utils.ceil32(s1) // 32) if compustate.gas < 0: return vm_exception('OOG PAYING FOR SHA3') if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') data = bytearray_to_bytestr(mem[s0:s0 + s1]) stk.append(utils.big_endian_to_int(utils.sha3(data))) elif op == 'ADDRESS': stk.append(utils.coerce_to_int(msg.to)) elif op == 'BALANCE': if ext.post_anti_dos_hardfork(): if not eat_gas(compustate, opcodes.BALANCE_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) stk.append(ext.get_balance(addr)) elif op == 'ORIGIN': stk.append(utils.coerce_to_int(ext.tx_origin)) elif op == 'CALLER': stk.append(utils.coerce_to_int(msg.sender)) elif op == 'CALLVALUE': stk.append(msg.value) elif op == 'CALLDATALOAD': stk.append(msg.data.extract32(stk.pop())) elif op == 'CALLDATASIZE': stk.append(msg.data.size) elif op == 'CALLDATACOPY': mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') msg.data.extract_copy(mem, mstart, dstart, size) elif op == 'CODESIZE': stk.append(len(code)) elif op == 'CODECOPY': mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') for i in range(size): if dstart + i < len(code): mem[mstart + i] = utils.safe_ord(code[dstart + i]) else: mem[mstart + i] = 0 elif op == 'RETURNDATACOPY': mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') if dstart + size > len(compustate.last_returned): return vm_exception('RETURNDATACOPY out of range') mem[mstart:mstart + size] = compustate.last_returned elif op == 'RETURNDATASIZE': stk.append(len(compustate.last_returned)) elif op == 'GASPRICE': stk.append(ext.tx_gasprice) elif op == 'EXTCODESIZE': if ext.post_anti_dos_hardfork(): if not eat_gas(compustate, opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) stk.append(len(ext.get_code(addr) or b'')) elif op == 'EXTCODECOPY': if ext.post_anti_dos_hardfork(): if not eat_gas(compustate, opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) start, s2, size = stk.pop(), stk.pop(), stk.pop() extcode = ext.get_code(addr) or b'' assert utils.is_string(extcode) if not mem_extend(mem, compustate, op, start, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') for i in range(size): if s2 + i < len(extcode): mem[start + i] = utils.safe_ord(extcode[s2 + i]) else: mem[start + i] = 0 elif opcode < 0x50: if op == 'BLOCKHASH': if ext.post_metropolis_hardfork() and False: bh_addr = ext.blockhash_store stk.append(ext.get_storage_data(bh_addr, stk.pop())) else: stk.append( utils.big_endian_to_int(ext.block_hash(stk.pop()))) elif op == 'COINBASE': stk.append(utils.big_endian_to_int(ext.block_coinbase)) elif op == 'TIMESTAMP': stk.append(ext.block_timestamp) elif op == 'NUMBER': stk.append(ext.block_number) elif op == 'DIFFICULTY': stk.append(ext.block_difficulty) elif op == 'GASLIMIT': stk.append(ext.block_gas_limit) elif opcode < 0x60: if op == 'POP': stk.pop() elif op == 'MLOAD': s0 = stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception('OOG EXTENDING MEMORY') stk.append(utils.bytes_to_int(mem[s0:s0 + 32])) elif op == 'MSTORE': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception('OOG EXTENDING MEMORY') mem[s0:s0 + 32] = utils.encode_int32(s1) elif op == 'MSTORE8': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 1): return vm_exception('OOG EXTENDING MEMORY') mem[s0] = s1 % 256 elif op == 'SLOAD': if ext.post_anti_dos_hardfork(): if not eat_gas(compustate, opcodes.SLOAD_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") stk.append(ext.get_storage_data(msg.to, stk.pop())) elif op == 'SSTORE': s0, s1 = stk.pop(), stk.pop() if msg.static: return vm_exception( 'Cannot SSTORE inside a static context') if ext.get_storage_data(msg.to, s0): gascost = opcodes.GSTORAGEMOD if s1 else opcodes.GSTORAGEKILL refund = 0 if s1 else opcodes.GSTORAGEREFUND else: gascost = opcodes.GSTORAGEADD if s1 else opcodes.GSTORAGEMOD refund = 0 if compustate.gas < gascost: return vm_exception('OUT OF GAS') compustate.gas -= gascost # adds neg gascost as a refund if below zero ext.add_refund(refund) ext.set_storage_data(msg.to, s0, s1) elif op == 'JUMP': compustate.pc = stk.pop() opnew = code[ compustate.pc] if compustate.pc < codelen else 0 jumped = True if opnew != JUMPDEST: return vm_exception('BAD JUMPDEST') elif op == 'JUMPI': s0, s1 = stk.pop(), stk.pop() if s1: compustate.pc = s0 opnew = code[ compustate.pc] if compustate.pc < codelen else 0 jumped = True if opnew != JUMPDEST: return vm_exception('BAD JUMPDEST') elif op == 'PC': stk.append(compustate.pc - 1) elif op == 'MSIZE': stk.append(len(mem)) elif op == 'GAS': stk.append(compustate.gas) # AFTER subtracting cost 1 elif op[:3] == 'DUP': # 0x7f - opcode is a negative number, -1 for 0x80 ... -16 for # 0x8f stk.append(stk[0x7f - opcode]) elif op[:4] == 'SWAP': # 0x8e - opcode is a negative number, -2 for 0x90 ... -17 for # 0x9f temp = stk[0x8e - opcode] stk[0x8e - opcode] = stk[-1] stk[-1] = temp elif op[:3] == 'LOG': """ 0xa0 ... 0xa4, 32/64/96/128/160 + len(data) gas a. Opcodes LOG0...LOG4 are added, takes 2-6 stack arguments MEMSTART MEMSZ (TOPIC1) (TOPIC2) (TOPIC3) (TOPIC4) b. Logs are kept track of during tx execution exactly the same way as suicides (except as an ordered list, not a set). Each log is in the form [address, [topic1, ... ], data] where: * address is what the ADDRESS opcode would output * data is mem[MEMSTART: MEMSTART + MEMSZ] * topics are as provided by the opcode c. The ordered list of logs in the transaction are expressed as [log0, log1, ..., logN]. """ depth = int(op[3:]) mstart, msz = stk.pop(), stk.pop() topics = [stk.pop() for x in range(depth)] compustate.gas -= msz * opcodes.GLOGBYTE if msg.static: return vm_exception('Cannot LOG inside a static context') if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') data = bytearray_to_bytestr(mem[mstart:mstart + msz]) ext.log(msg.to, topics, data) log_log.trace('LOG', to=msg.to, topics=topics, data=list(map(utils.safe_ord, data))) # print('LOG', msg.to, topics, list(map(ord, data))) elif op == 'CREATE': value, mstart, msz = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') if msg.static: return vm_exception( 'Cannot CREATE inside a static context') if ext.get_balance(msg.to) >= value and msg.depth < MAX_DEPTH: cd = CallData(mem, mstart, msz) ingas = compustate.gas if ext.post_anti_dos_hardfork(): ingas = all_but_1n(ingas, opcodes.CALL_CHILD_LIMIT_DENOM) create_msg = Message(msg.to, b'', value, ingas, cd, msg.depth + 1) o, gas, addr = ext.create(create_msg) if o: stk.append(utils.coerce_to_int(addr)) else: stk.append(0) compustate.gas = compustate.gas - ingas + gas else: stk.append(0) elif op in ('CALL', 'CALLCODE', 'DELEGATECALL', 'STATICCALL'): # Pull arguments from the stack if op in ('CALL', 'CALLCODE'): gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() else: gas, to, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() value = 0 # Static context prohibition if msg.static and value > 0: return vm_exception( 'Cannot make a non-zero-value call inside a static context' ) # Expand memory if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ not mem_extend(mem, compustate, op, memoutstart, memoutsz): return vm_exception('OOG EXTENDING MEMORY') to = utils.int_to_addr(to) # Extra gas costs based on hard fork-dependent factors extra_gas = (not ext.account_exists(to)) * (op == 'CALL') * (value > 0 or not ext.post_clearing_hardfork()) * opcodes.GCALLNEWACCOUNT + \ (value > 0) * opcodes.GCALLVALUETRANSFER + \ ext.post_anti_dos_hardfork() * opcodes.CALL_SUPPLEMENTAL_GAS # Compute child gas limit if ext.post_anti_dos_hardfork(): if compustate.gas < extra_gas: return vm_exception('OUT OF GAS', needed=extra_gas) gas = min( gas, all_but_1n(compustate.gas - extra_gas, opcodes.CALL_CHILD_LIMIT_DENOM)) else: if compustate.gas < gas + extra_gas: return vm_exception('OUT OF GAS', needed=gas + extra_gas) submsg_gas = gas + opcodes.GSTIPEND * (value > 0) # Verify that there is sufficient balance and depth if ext.get_balance(msg.to) < value or msg.depth >= MAX_DEPTH: compustate.gas -= (gas + extra_gas - submsg_gas) stk.append(0) else: # Subtract gas from parent compustate.gas -= (gas + extra_gas) assert compustate.gas >= 0 cd = CallData(mem, meminstart, meminsz) # Generate the message if op == 'CALL': call_msg = Message(msg.to, to, value, submsg_gas, cd, msg.depth + 1, code_address=to, static=msg.static) elif ext.post_homestead_hardfork( ) and op == 'DELEGATECALL': call_msg = Message(msg.sender, msg.to, msg.value, submsg_gas, cd, msg.depth + 1, code_address=to, transfers_value=False, static=msg.static) elif op == 'DELEGATECALL': return vm_exception('OPCODE INACTIVE') elif op == 'CALLCODE': call_msg = Message(msg.to, msg.to, value, submsg_gas, cd, msg.depth + 1, code_address=to, static=msg.static) elif op == 'STATICCALL': call_msg = Message(msg.to, to, value, submsg_gas, cd, msg.depth + 1, code_address=to, static=True) else: raise Exception("Lolwut") # Get result result, gas, data = ext.msg(call_msg) if result == 0: stk.append(0) else: stk.append(1) # Set output memory for i in range(min(len(data), memoutsz)): mem[memoutstart + i] = data[i] compustate.gas += gas compustate.last_returned = bytearray(data) elif op == 'RETURN': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') return peaceful_exit('RETURN', compustate.gas, mem[s0:s0 + s1]) elif op == 'REVERT': if not ext.post_metropolis_hardfork(): return vm_exception('Opcode not yet enabled') s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') return revert(compustate.gas, mem[s0:s0 + s1]) elif op == 'SUICIDE': if msg.static: return vm_exception( 'Cannot SUICIDE inside a static context') to = utils.encode_int(stk.pop()) to = ((b'\x00' * (32 - len(to))) + to)[12:] xfer = ext.get_balance(msg.to) if ext.post_anti_dos_hardfork(): extra_gas = opcodes.SUICIDE_SUPPLEMENTAL_GAS + \ (not ext.account_exists( to)) * (xfer > 0 or not ext.post_clearing_hardfork()) * opcodes.GCALLNEWACCOUNT if not eat_gas(compustate, extra_gas): return vm_exception("OUT OF GAS") ext.set_balance(to, ext.get_balance(to) + xfer) ext.set_balance(msg.to, 0) ext.add_suicide(msg.to) log_msg.debug('SUICIDING', addr=utils.checksum_encode(msg.to), to=utils.checksum_encode(to), xferring=xfer) return 1, compustate.gas, [] # assert utils.is_numeric(compustate.gas) # this is slow! # for a in stk: # assert is_numeric(a), (op, stk) # assert a >= 0 and a < 2**256, (a, op, stk) # if not jumped: # assert compustate.pc == nextpos # compustate.pc = nextpos if compustate.pc >= codelen: return peaceful_exit('CODE OUT OF RANGE', compustate.gas, []) return vm_exception('INVALID JUMP')
def mk_fake_header(blknum): if blknum not in fake_headers: fake_headers[blknum] = FakeHeader(sha3(to_string(blknum))) return fake_headers[blknum]
def mk_logout(validator_index, epoch, key): sighash = utils.sha3(rlp.encode([validator_index, epoch])) v, r, s = utils.ecdsa_raw_sign(sighash, key) sig = utils.encode_int32(v) + utils.encode_int32(r) + utils.encode_int32(s) return rlp.encode([validator_index, epoch, sig])
self.transactions = transactions or [] self.uncles = uncles or [] self.uncles = list(self.uncles) def __getattribute__(self, name): try: return rlp.Serializable.__getattribute__(self, name) except AttributeError: return getattr(self.header, name) @property def transaction_count(self): return len(self.transactions) BLANK_UNCLES_HASH = sha3(rlp.encode([])) class FakeHeader(): def __init__(self, hash=b'\x00' * 32, number=0, timestamp=0, difficulty=1, gas_limit=3141592, gas_used=0, uncles_hash=BLANK_UNCLES_HASH): self.hash = hash self.number = number self.timestamp = timestamp self.difficulty = difficulty
def signing_hash(self): return utils.sha3(rlp.encode(self, BlockHeader.exclude(['extra_data'])))
def mining_hash(self): return utils.sha3( rlp.encode(self, BlockHeader.exclude(['mixhash', 'nonce'])))