def verify(block, parent): def must_equal(what, a, b): if not a == b: raise VerificationFailed(what, a, '==', b) if not block.timestamp >= parent.timestamp: raise VerificationFailed('timestamp', block.timestamp, '>=', parent.timestamp) if not block.timestamp <= time.time() + 900: raise VerificationFailed('timestamps', block.timestamp, '<=', time.time() + 900) block2 = blocks.Block.init_from_parent(parent, block.coinbase, extra_data=block.extra_data, timestamp=block.timestamp, uncles=block.uncles) must_equal('difficulty', block2.difficulty, block.difficulty) must_equal('gas limit', block2.gas_limit, block.gas_limit) for i in range(block.transaction_count): tx, s, g = rlp.decode( block.transactions.get(rlp.encode(utils.encode_int(i)))) tx = transactions.Transaction.create(tx) if not tx.startgas + block2.gas_used <= block.gas_limit: raise VerificationFailed('gas_limit', tx.startgas + block2.gas_used, '<=', block.gas_limit) apply_transaction(block2, tx) must_equal('tx state root', s, block2.state.root_hash) must_equal('tx gas used', g, utils.encode_int(block2.gas_used)) block2.finalize() must_equal('block state root', block2.state.root_hash, block.state.root_hash) must_equal('block gas used', block2.gas_used, block.gas_used) return True
def mk_independent_transaction_spv_proof(block, index): print block, index, block._list_transactions() block = blocks.Block.init_from_header(block.list_header()) tx = transactions.Transaction.create(block.get_transaction(index)[0]) if index > 0: _, pre_med, pre_gas = block.get_transaction(index - 1) else: pre_med, pre_gas = block.get_parent().state_root, 0 block.state_root = pre_med block.gas_used = pre_gas nodes = mk_transaction_spv_proof(block, tx) nodes.extend( block.transactions.produce_spv_proof( rlp.encode(utils.encode_int(index)))) if index > 0: nodes.extend( block.transactions.produce_spv_proof( rlp.encode(utils.encode_int(index - 1)))) nodes = map(rlp.decode, list(set(map(rlp.encode, nodes)))) return rlp.encode([ utils.encode_int(64), block.get_parent().list_header(), block.list_header(), utils.encode_int(index), nodes ])
def apply_tx(block,tx): fee = tx.gasprice * tx.startgas addrstate = block.state.get(tx.sender.decode('hex')) if not addrstate: raise Exception("Sending from a not-yet-existent account!") if decode_int(addrstate[NONCE_INDEX]) != tx.nonce: print decode_int(addrstate[NONCE_INDEX]), tx.nonce raise Exception("Invalid nonce!") if decode_int(addrstate[BALANCE_INDEX]) < fee: raise Exception("Not enough in account to pay fee!") addrstate[NONCE_INDEX] = encode_int(decode_int(addrstate[NONCE_INDEX])+1) addrstate[BALANCE_INDEX] = encode_int(decode_int(addrstate[BALANCE_INDEX])-fee) block.state.update(tx.sender.decode('hex'),addrstate) block.gas_consumed += fee medroot = block.state.root message_gas = tx.startgas - GTXDATA * len(tx.data) message = Message(tx.sender,tx.to,tx.value,message_gas,tx.data) if tx.to: s,g,d = apply_msg(block,tx,message) else: s,g = create_contract(block,tx,message) if not s: block.state.root = medroot minerstate = block.state.get(block.coinbase) minerstate[BALANCE_INDEX] = encode_int(decode_int(minerstate[BALANCE_INDEX])+fee) block.state.update(block.coinbase,minerstate) else: addrstate[BALANCE_INDEX] = encode_int(decode_int(addrstate[BALANCE_INDEX])+tx.gasprice * g) block.state.update(tx.sender.decode('hex'),addrstate) minerstate = block.state.get(block.coinbase.decode('hex')) or ['','','',''] minerstate[BALANCE_INDEX] = encode_int(decode_int(minerstate[BALANCE_INDEX])+(fee - g * tx.gasprice)) block.state.update(block.coinbase.decode('hex'),minerstate)
def create_contract(block,tx,msg): oldroot = block.state.root senderstate = block.state.get(msg.sender) or ['','','',''] recvstate = ['','',sha3(msg.data),''] recvaddr = sha3(rlp.encode([msg.sender,senderstate[NONCE_INDEX]]))[12:] code = msg.data statedb.put(sha3(msg.data),msg.data) compustate = Compustate(gas=msg.gas) # Not enough vaue to send, instaquit if decode_int(senderstate[BALANCE_INDEX]) < msg.value: recvstate[2] = [] block.state.update(recvaddr,recvstate) return recvaddr, compustate.gas # Transfer value and update nonce senderstate[BALANCE_INDEX] = encode_int(decode_int(senderstate[BALANCE_INDEX])-msg.value) senderstate[NONCE_INDEX] = encode_int(decode_int(senderstate[NONCE_INDEX])+1) recvstate[BALANCE_INDEX] = encode_int(decode_int(senderstate[BALANCE_INDEX])+msg.value) block.state.update(msg.sender.decode('hex'),senderstate) block.state.update(recvaddr,recvstate) # Temporary pre-POC5: don't do the code/init thing return recvaddr, compustate.gas # Main loop while 1: o = apply_op(block,tx,msg,msg.data,compustate.op) if o is not None: if o == OUT_OF_GAS: block.state.root = oldroot return 0, 0 else: recvstate = block.state.get(recvaddr) recvstate[CODE_INDEX] = sha3(map(chr,o)) statedb.put(sha3(map(chr,o)),map(chr,o)) block.state.update(recvaddr,recvstate) return recvaddr, recvstate
def mk_blank_acct(self): if not hasattr(self, '_blank_acct'): codehash = utils.sha3('') self.state.db.put(codehash, '') self._blank_acct = [ utils.encode_int(0), utils.encode_int(0), trie.BLANK_ROOT, codehash ] return self._blank_acct[:]
def mk_blank_acct(self): if not hasattr(self, '_blank_acct'): codehash = utils.sha3('') self.state.db.put(codehash, '') self._blank_acct = [utils.encode_int(0), utils.encode_int(0), trie.BLANK_ROOT, codehash] return self._blank_acct[:]
def serialize(self): txlist = [x.serialize() for x in self.transactions] header = [ encode_int(self.number), self.prevhash, sha3(rlp.encode(self.uncles)), self.coinbase.decode('hex'), self.state.root, sha3(rlp.encode(txlist)), encode_int(self.difficulty), encode_int(self.timestamp), self.extradata, encode_int(self.nonce) ] return rlp.encode([header, txlist, self.uncles])
def serialize(self): txlist = [x.serialize() for x in self.transactions] header = [encode_int(self.number), self.prevhash, sha3(rlp.encode(self.uncles)), self.coinbase.decode('hex'), self.state.root, sha3(rlp.encode(txlist)), encode_int(self.difficulty), encode_int(self.timestamp), self.extradata, encode_int(self.nonce)] return rlp.encode([header, txlist, self.uncles])
def create_contract(block,tx,msg): snapshot = block.snapshot() sender = msg.sender.decode('hex') if len(msg.sender) == 40 else msg.sender nonce = encode_int(block.get_nonce(msg.sender)) recvaddr = sha3(rlp.encode([sender,nonce]))[12:] code = msg.data # Transfer value, instaquit if not enough block.delta_balance(recvaddr,msg.value) o = block.delta_balance(msg.sender,msg.value) if not o: return 0, msg.gas block.set_code(recvaddr,msg.data) compustate = Compustate(gas=msg.gas) # Temporary pre-POC5: don't do the code/init thing return recvaddr, compustate.gas # Main loop while 1: o = apply_op(block,tx,msg,msg.data,compustate.op) if o is not None: if o == OUT_OF_GAS: block.state.root = oldroot return 0, 0 else: block.set_code(''.join(map(chr,o))) return recvaddr, compustate.gas
def set_storage_data(self,address,index,val): t = self.get_storage(address) if val: t.update(utils.coerce_to_bytes(index),encode_int(val)) else: t.delete(utils.coerce_to_bytes(index)) self.set_index(address,STORAGE_INDEX,t.root)
def apply_tx(block, tx): if not tx.sender: raise Exception("Trying to apply unsigned transaction!") acctnonce = block.get_nonce(tx.sender) if acctnonce != tx.nonce: raise Exception("Invalid nonce! Sender %s tx %s" % (acctnonce, tx.nonce)) o = block.delta_balance(tx.sender, -tx.gasprice * tx.startgas) if not o: raise Exception("Insufficient balance to pay fee!") block.increment_nonce(tx.sender) snapshot = block.snapshot() message_gas = tx.startgas - GTXDATA * len(tx.serialize()) - GTXCOST message = Message(tx.sender, tx.to, tx.value, message_gas, tx.data) if tx.to: result, gas, data = apply_msg(block, tx, message) else: result, gas = create_contract(block, tx, message) if not result: # 0 = OOG failure in both cases block.revert(snapshot) block.gas_used += tx.startgas block.delta_balance(block.coinbase, tx.gasprice * tx.startgas) output = OUT_OF_GAS else: block.delta_balance(tx.sender, tx.gasprice * gas) block.delta_balance(block.coinbase, tx.gasprice * (tx.startgas - gas)) block.gas_used += tx.startgas - gas output = ''.join(map(chr, data)) if tx.to else result.encode('hex') tx_data = [tx.serialize(), block.state.root, encode_int(block.gas_used)] block.add_transaction_to_list(tx_data) success = output is not OUT_OF_GAS return success, output if success else ''
def _list_transactions(self): # returns [[tx_lst_serialized, state_root, gas_used_encoded],...] txlist = [] for i in range(self.transaction_count): txlist.append(rlp.decode( self.transactions.get(utils.encode_int(i)))) return txlist
def set_storage_data(self, address, index, val): t = self.get_storage(address) if val: t.update(utils.coerce_to_bytes(index), encode_int(val)) else: t.delete(utils.coerce_to_bytes(index)) self.set_index(address, STORAGE_INDEX, t.root)
def set_storage_data(self, address, index, val): t = self.get_storage(address) if val: t.update(utils.coerce_to_bytes(index), utils.encode_int(val)) else: t.delete(utils.coerce_to_bytes(index)) self._set_acct_item(address, 'storage', t.root_hash)
def create_contract(block, tx, msg): snapshot = block.snapshot() sender = msg.sender.decode('hex') if len(msg.sender) == 40 else msg.sender nonce = utils.encode_int(block.get_nonce(msg.sender)) recvaddr = utils.sha3(rlp.encode([sender, nonce]))[12:] assert not block.get_code(recvaddr) msg.to = recvaddr block.increment_nonce(msg.sender) # Transfer value, instaquit if not enough o = block.transfer_value(msg.sender, msg.to, msg.value) if not o: return 0, msg.gas compustate = Compustate(gas=msg.gas) # Main loop while 1: o = apply_op(block, tx, msg, msg.data, compustate) if o is not None: if o == OUT_OF_GAS: block.revert(snapshot) return 0, 0, [] else: for s in block.suicides: block.state.delete(utils.encode_addr(s)) block.set_code(recvaddr, ''.join(map(chr, o))) return recvaddr, compustate.gas, o
def listen(self, log, noprint=True): if not len(log.topics) or log.topics[0] not in self.event_data: return types = self.event_data[log.topics[0]]['types'] name = self.event_data[log.topics[0]]['name'] names = self.event_data[log.topics[0]]['names'] indexed = self.event_data[log.topics[0]]['indexed'] indexed_types = [types[i] for i in range(len(types)) if indexed[i]] unindexed_types = [ types[i] for i in range(len(types)) if not indexed[i] ] # print('listen', encode_hex(log.data), log.topics) deserialized_args = decode_abi(unindexed_types, log.data) o = {} c1, c2 = 0, 0 for i in range(len(names)): if indexed[i]: topic_bytes = utils.zpad(utils.encode_int(log.topics[c1 + 1]), 32) o[names[i]] = decode_single(process_type(indexed_types[c1]), topic_bytes) c1 += 1 else: o[names[i]] = deserialized_args[c2] c2 += 1 o["_event_type"] = utils.to_string(name) if not noprint: print(o) return o
def to_dict(self, with_state=False, full_transactions=False): """ serializes the block with_state: include state for all accounts full_transactions: include serialized tx (hashes otherwise) """ self.commit_state() b = {} for name, typ, default in block_structure: b[name] = utils.printers[typ](getattr(self, name)) txlist = [] for i in range(self.transaction_count): tx_rlp = self.transactions.get(rlp.encode(utils.encode_int(i))) tx, msr, gas = rlp.decode(tx_rlp) if full_transactions: txjson = transactions.Transaction.create(tx).to_dict() else: txjson = utils.sha3(rlp.descend(tx_rlp, 0)).encode('hex') # tx hash txlist.append({ "tx": txjson, "medstate": msr.encode('hex'), "gas": str(utils.decode_int(gas)) }) b["transactions"] = txlist if with_state: state_dump = {} for address, v in self.state.to_dict().iteritems(): state_dump[address.encode('hex')] = self.account_to_dict( address) b['state'] = state_dump return b
def to_dict(self, with_state=False, full_transactions=False, with_storage_roots=False): """ serializes the block with_state: include state for all accounts full_transactions: include serialized tx (hashes otherwise) """ b = {} for name, typ, default in block_structure: b[name] = utils.printers[typ](getattr(self, name)) txlist = [] for i in range(self.transaction_count): tx_rlp = self.transactions.get(rlp.encode(utils.encode_int(i))) tx, msr, gas = rlp.decode(tx_rlp) if full_transactions: txjson = transactions.Transaction.create(tx).to_dict() else: txjson = utils.sha3(rlp.descend(tx_rlp, 0)).encode('hex') # tx hash txlist.append({ "tx": txjson, "medstate": msr.encode('hex'), "gas": str(utils.decode_int(gas)) }) b["transactions"] = txlist if with_state: state_dump = {} for address, v in self.state.to_dict().iteritems(): state_dump[address.encode('hex')] = \ self.account_to_dict(address, with_storage_roots) b['state'] = state_dump return b
def mk_transaction_receipt(self, tx): o = [ self.state_root, utils.encode_int(self.gas_used), tx.log_bloom_b64(), [x.serialize() for x in tx.logs] ] return rlp.encode(o)
def _list_transactions(self): # returns [[tx_lst_serialized, state_root, gas_used_encoded],...] txlist = [] for i in range(self.transaction_count): txlist.append( rlp.decode(self.transactions.get(utils.encode_int(i)))) return txlist
def _add_transaction_to_list(self, tx_serialized, state_root, gas_used_encoded): # adds encoded data # FIXME: the constructor should get objects data = [tx_serialized, state_root, gas_used_encoded] self.transactions.update(utils.encode_int(self.transaction_count), data) self.transaction_count += 1
def serialize(self): return [ self.address.decode('hex'), [utils.zpad(utils.encode_int(x), 32) for x in self.topics], # why zpad? self.data ]
def listen(self, log, noprint=True): if not len(log.topics) or log.topics[0] not in self.event_data: return types = self.event_data[log.topics[0]]['types'] name = self.event_data[log.topics[0]]['name'] names = self.event_data[log.topics[0]]['names'] indexed = self.event_data[log.topics[0]]['indexed'] indexed_types = [types[i] for i in range(len(types)) if indexed[i]] unindexed_types = [types[i] for i in range(len(types)) if not indexed[i]] # print('listen', encode_hex(log.data), log.topics) deserialized_args = decode_abi(unindexed_types, log.data) o = {} c1, c2 = 0, 0 for i in range(len(names)): if indexed[i]: topic_bytes = utils.zpad(utils.encode_int(log.topics[c1 + 1]), 32) o[names[i]] = decode_single(process_type(indexed_types[c1]), topic_bytes) c1 += 1 else: o[names[i]] = deserialized_args[c2] c2 += 1 o["_event_type"] = utils.to_string(name) if not noprint: print(o) return o
def create_contract(block, tx, msg): snapshot = block.snapshot() sender = msg.sender.decode('hex') if len(msg.sender) == 40 else msg.sender nonce = encode_int(block.get_nonce(msg.sender)) recvaddr = sha3(rlp.encode([sender, nonce]))[12:] code = msg.data # Transfer value, instaquit if not enough block.delta_balance(recvaddr, msg.value) o = block.delta_balance(msg.sender, msg.value) if not o: return 0, msg.gas block.set_code(recvaddr, msg.data) compustate = Compustate(gas=msg.gas) # Temporary pre-POC5: don't do the code/init thing return recvaddr, compustate.gas # Main loop while 1: o = apply_op(block, tx, msg, msg.data, compustate.op) if o is not None: if o == OUT_OF_GAS: block.state.root = oldroot return 0, 0 else: block.set_code(''.join(map(chr, o))) return recvaddr, compustate.gas
def mk_independent_transaction_spv_proof(block, index): print block, index, block._list_transactions() block = blocks.Block.init_from_header(block.list_header()) tx = transactions.Transaction.create(block.get_transaction(index)[0]) if index > 0: _, pre_med, pre_gas = block.get_transaction(index - 1) else: pre_med, pre_gas = block.get_parent().state_root, 0 block.state_root = pre_med block.gas_used = pre_gas nodes = mk_transaction_spv_proof(block, tx) nodes.extend(block.transactions.produce_spv_proof(rlp.encode(utils.encode_int(index)))) if index > 0: nodes.extend(block.transactions.produce_spv_proof(rlp.encode(utils.encode_int(index - 1)))) nodes = map(rlp.decode, list(set(map(rlp.encode, nodes)))) return rlp.encode([utils.encode_int(64), block.get_parent().list_header(), block.list_header(), utils.encode_int(index), nodes])
def delta_index(self,address,index,value): if len(address) == 40: address = address.decode('hex') acct = self.state.get(address) or ['','','',''] if decode_int(acct[index]) + value < 0: return False acct[index] = encode_int(decode_int(acct[index])+value) self.state.update(address,acct) return True
def _add_transaction_to_list(self, tx_lst_serialized, state_root, gas_used_encoded): # adds encoded data # FIXME: the constructor should get objects assert isinstance(tx_lst_serialized, list) data = [tx_lst_serialized, state_root, gas_used_encoded] self.transactions.update(utils.encode_int(self.transaction_count), rlp.encode(data)) self.transaction_count += 1
def _add_transaction_to_list(self, tx_lst_serialized, state_root, gas_used_encoded): # adds encoded data # FIXME: the constructor should get objects assert isinstance(tx_lst_serialized, list) data = [tx_lst_serialized, state_root, gas_used_encoded] self.transactions.update( utils.encode_int(self.transaction_count), rlp.encode(data)) self.transaction_count += 1
def delta_index(self, address, index, value): if len(address) == 40: address = address.decode('hex') acct = self.state.get(address) or ['', '', '', ''] if decode_int(acct[index]) + value < 0: return False acct[index] = encode_int(decode_int(acct[index]) + value) self.state.update(address, acct) return True
def to_dict(self, with_state=False, full_transactions=False, with_storage_roots=False, with_uncles=False): """ serializes the block with_state: include state for all accounts full_transactions: include serialized tx (hashes otherwise) with_uncles: include uncle hashes """ b = {} for name, typ, default in block_structure: b[name] = utils.printers[typ](getattr(self, name)) txlist = [] for i in range(self.transaction_count): tx_rlp = self.transactions.get(rlp.encode(utils.encode_int(i))) tx = rlp.decode(tx_rlp) receipt_rlp = self.receipts.get(rlp.encode(utils.encode_int(i))) msr, gas, mybloom, mylogs = rlp.decode(receipt_rlp) if full_transactions: txjson = transactions.Transaction.create(tx).to_dict() else: # tx hash txjson = utils.sha3(rlp.descend(tx_rlp, 0)).encode('hex') txlist.append({ "tx": txjson, "medstate": msr.encode('hex'), "gas": str(utils.decode_int(gas)), "logs": mylogs, "bloom": mybloom.encode('hex') }) b["transactions"] = txlist if with_state: state_dump = {} for address, v in self.state.to_dict().iteritems(): state_dump[address.encode('hex')] = \ self.account_to_dict(address, with_storage_roots) b['state'] = state_dump if with_uncles: b['uncles'] = [ utils.sha3(rlp.encode(u)).encode('hex') for u in self.uncles ] return b
def _add_transactions(self, blk): "'tx_hash' -> 'rlp([blockhash,tx_number])" for i in range(blk.transaction_count): i_enc = utils.encode_int(i) # work on rlp data to avoid unnecessary de/serialization td = blk.transactions.get(rlp.encode(i_enc)) tx = rlp.descend(td, 0) key = utils.sha3(tx) value = rlp.encode([blk.hash, i_enc]) self.db.put(key, value)
def verify(block, parent): assert block.timestamp >= parent.timestamp assert block.timestamp <= time.time() + 900 block2 = blocks.init_from_parent(parent, block.coinbase, block.extra_data, block.timestamp) assert block2.difficulty == block.difficulty assert block2.gas_limit == block.gas_limit for i in range(block.transaction_count): tx, s, g = block.transactions.get(utils.encode_int(i)) tx = transactions.Transaction.deserialize(tx) assert tx.startgas + block2.gas_used <= block.gas_limit block2.apply_tx(tx) assert s == block2.state.root assert g == utils.encode_int(block2.gas_used) finalize(block2) assert block2.state.root == block.state.root assert block2.gas_consumed == block.gas_consumed return True
def serialize(self): txlist = [] for i in range(self.transaction_count): txlist.append(self.transactions.get(utils.encode_int(i))) self.state_root = self.state.root self.tx_list_root = self.transactions.root self.uncles_hash = sha3(rlp.encode(self.uncles)) header = [] for name, typ, default in block_structure: header.append(utils.encoders[typ](getattr(self, name))) return rlp.encode([header, txlist, self.uncles])
def verify(block, parent): assert block.timestamp >= parent.timestamp assert block.timestamp <= time.time() + 900 block2 = blocks.Block.init_from_parent(parent, block.coinbase, extra_data=block.extra_data, timestamp=block.timestamp, uncles=block.uncles) assert block2.difficulty == block.difficulty assert block2.gas_limit == block.gas_limit block2.finalize() for i in range(block.transaction_count): tx, s, g = rlp.decode(block.transactions.get(utils.encode_int(i))) tx = transactions.Transaction.create(tx) assert tx.startgas + block2.gas_used <= block.gas_limit apply_transaction(block2, tx) assert s == block2.state.root_hash assert g == utils.encode_int(block2.gas_used) assert block2.state.root_hash == block.state.root_hash assert block2.gas_used == block.gas_used return True
def chain_difficulty(self): # calculate the summarized_difficulty (on the fly for now) if self.is_genesis(): return self.difficulty elif 'difficulty:'+self.hex_hash() in self.state.db: return utils.decode_int( self.state.db.get('difficulty:'+self.hex_hash())) else: o = self.difficulty + self.get_parent().chain_difficulty() self.state.db.put('difficulty:'+self.hex_hash(), utils.encode_int(o)) return o
def chain_difficulty(self): # calculate the summarized_difficulty if self.is_genesis(): return self.difficulty elif "difficulty:" + self.hex_hash() in self.state.db: return utils.decode_int(self.state.db.get("difficulty:" + self.hex_hash())) else: _idx, _typ, _ = block_structure_rev["difficulty"] o = self.difficulty + self.get_parent().chain_difficulty() o += sum([utils.decoders[_typ](u[_idx]) for u in self.uncles]) self.state.db.put("difficulty:" + self.hex_hash(), utils.encode_int(o)) return o
def chain_difficulty(self): # calculate the summarized_difficulty (on the fly for now) if self.is_genesis(): return self.difficulty elif 'difficulty:' + self.hex_hash() in self.state.db: return utils.decode_int( self.state.db.get('difficulty:' + self.hex_hash())) else: o = self.difficulty + self.get_parent().chain_difficulty() self.state.db.put('difficulty:' + self.hex_hash(), utils.encode_int(o)) return o
def serialize(self,signed=True): return rlp.encode([encode_int(self.nonce), encode_int(self.value), encode_int(self.gasprice), encode_int(self.startgas), self.to.decode('hex'), self.data, encode_int(self.v), encode_int(self.r), encode_int(self.s)][:9 if signed else 6])
def serialize(self, signed=True): return rlp.encode([encode_int(self.nonce), encode_int(self.value), encode_int(self.gasprice), encode_int(self.startgas), utils.coerce_addr_to_bin(self.to), self.data, encode_int(self.v), encode_int(self.r), encode_int(self.s)][:9 if signed else 6])
def mine(full_size, dataset, header, difficulty): from random import randint # computing difficulty target target = zpad(encode_int(2**256 // difficulty), 64)[::-1] # nonces are randomly generated nonce = randint(0, 2**64) while hashimoto_full(full_size, dataset, header, nonce) > target: nonce = (nonce + 1) % 2**64 return nonce
def chain_difficulty(self): # calculate the summarized_difficulty if self.is_genesis(): return self.difficulty elif 'difficulty:' + self.hex_hash() in self.state.db: return utils.decode_int( self.state.db.get('difficulty:' + self.hex_hash())) else: _idx, _typ, _ = block_structure_rev['difficulty'] o = self.difficulty + self.get_parent().chain_difficulty() o += sum([self.decoders[_typ](u[_idx]) for u in self.uncles]) self.state.db.put('difficulty:' + self.hex_hash(), utils.encode_int(o)) return o
def serialize(self, signed=True): return rlp.encode([ encode_int(self.nonce), encode_int(self.value), encode_int(self.gasprice), encode_int(self.startgas), utils.coerce_addr_to_bin(self.to), self.data, encode_int(self.v), encode_int(self.r), encode_int(self.s) ][:9 if signed else 6])
def verify(block, parent): if block.timestamp < parent.timestamp: print block.timestamp, parent.timestamp assert block.timestamp >= parent.timestamp assert block.timestamp <= time.time() + 900 block2 = blocks.Block.init_from_parent(parent, block.coinbase, block.extra_data, block.timestamp) assert block2.difficulty == block.difficulty assert block2.gas_limit == block.gas_limit block2.finalize() # this is the first potential state change for i in range(block.transaction_count): tx, s, g = block.transactions.get(utils.encode_int(i)) tx = transactions.Transaction.deserialize(tx) print tx.startgas, block2.gas_used, block.gas_limit assert tx.startgas + block2.gas_used <= block.gas_limit apply_tx(block2, tx) assert s == block2.state.root assert g == utils.encode_int(block2.gas_used) assert block2.state.root == block.state.root assert block2.gas_used == block.gas_used return True
def _delta_item(self, address, index, value): ''' add value to account item :param address: account address, can be binary or hex string :param index: item index :param value: can be positive or negative ''' if len(address) == 40: address = address.decode('hex') acct = self.state.get(address) or ['', '', '', ''] if decode_int(acct[index]) + value < 0: return False acct[index] = encode_int(decode_int(acct[index]) + value) self.state.update(address, acct) return True
def apply_msg(block,tx,msg): oldroot = block.state.root senderstate = block.state.get(msg.sender) recvstate = block.state.get(msg.to) or ['','','',''] codehash = recvstate[CODE_INDEX] code = statedb.get(codehash) compustate = Compustate(gas=msg.gas) # Not enough value to send, instaquit if decode_int(senderstate[BALANCE_INDEX]) < msg.value: return 1, compustate.gas, [] # Transfer value senderstate[BALANCE_INDEX] = encode_int(decode_int(senderstate[BALANCE_INDEX]) - msg.value) recvstate[BALANCE_INDEX] = encode_int(decode_int(senderstate[BALANCE_INDEX]) + msg.value) block.state.update(msg.sender,senderstate) block.state.update(msg.to,recvstate) # Main loop while 1: o = apply_op(block,tx,msg,code,compustate,op) if o is not None: if o == OUT_OF_GAS: block.state.root = oldroot return 0, 0, [] else: return 1, compustate.gas, o
def _delta_item(self, address, param, value): ''' add value to account item :param address: account address, can be binary or hex string :param param: parameter to increase/decrease :param value: can be positive or negative ''' if len(address) == 40: address = address.decode('hex') acct = self.state.get(address) or ['', '', '', ''] index = acct_structure_rev[param][0] if utils.decode_int(acct[index]) + value < 0: return False acct[index] = utils.encode_int(utils.decode_int(acct[index]) + value) self.state.update(address, acct) return True
def create_contract(block, tx, msg): sender = msg.sender.decode('hex') if len(msg.sender) == 40 else msg.sender if tx.sender != msg.sender: block.increment_nonce(msg.sender) nonce = utils.encode_int(block.get_nonce(msg.sender) - 1) msg.to = utils.sha3(rlp.encode([sender, nonce]))[12:].encode('hex') assert not block.get_code(msg.to) res, gas, dat = apply_msg(block, tx, msg, msg.data) if res: block.set_code(msg.to, ''.join(map(chr, dat))) return utils.coerce_to_int(msg.to), gas, dat else: if tx.sender != msg.sender: block.decrement_nonce(msg.sender) block.del_account(msg.to) return res, gas, dat
def OP_CREATE(): value, mstart, msz = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, msgtop.compustate, '', mstart, msz): return drop(OUT_OF_GAS) if block.get_balance(msgtop.to) >= value: sender = msgtop.to.decode('hex') if len( msgtop.to) == 40 else msgtop.to block.increment_nonce(msgtop.to) data = [0] * ((msz >> 5) + 1) copy32(mem, data, mstart, 0, msz) create_msg = Message(msgtop.to, '', value, gaz() - 100, data, msz) msgtop.compustate.gas -= gaz() - 100 nonce = utils.encode_int(block.get_nonce(msgtop.to) - 1) create_msg.to = utils.sha3(rlp.encode([sender, nonce]))[12:].encode('hex') special[0] = 'create' special[1] = create_msg special[2] = ''.join([chr(x) for x in extract_bytes(data, 0, msz)]) else: stk.append(0)
def create_contract(ext, msg): sender = msg.sender.decode('hex') if len(msg.sender) == 40 else msg.sender if ext.tx_origin != msg.sender: ext._block.increment_nonce(msg.sender) nonce = utils.encode_int(ext._block.get_nonce(msg.sender) - 1) msg.to = utils.sha3(rlp.encode([sender, nonce]))[12:].encode('hex') assert not ext.get_code(msg.to) res, gas, dat = apply_msg(ext, msg, msg.data.extract_all()) if res: if not len(dat): return 1, gas, '' gcost = len(dat) * opcodes.GCONTRACTBYTE if gas >= gcost: gas -= gcost else: dat = [] log_msg.debug('CONTRACT CREATION OOG', have=gas, want=gcost) ext._block.set_code(msg.to, ''.join(map(chr, dat))) return 1, gas, msg.to else: return 0, gas, ''
def to_dict(self): self.commit_state() b = {} for name, typ, default in block_structure: b[name] = utils.printers[typ](getattr(self, name)) b["state"] = {} for address, v in self.state.to_dict().iteritems(): b["state"][address.encode('hex')] = self.account_to_dict(address) txlist = [] for i in range(self.transaction_count): td = self.transactions.get(rlp.encode(utils.encode_int(i))) tx = rlp.descend(td, 0) msr = rlp.descend_to_val(td, 1) gas = rlp.descend_to_val(td, 2) txjson = transactions.Transaction.deserialize(tx).to_dict() txlist.append({ "tx": txjson, "medstate": msr.encode('hex'), "gas": str(utils.decode_int(gas)) }) b["transactions"] = txlist return b
def create_contract(block, tx, msg): snapshot = block.snapshot() sender = msg.sender.decode('hex') if len(msg.sender) == 40 else msg.sender nonce = utils.encode_int(block.get_nonce(msg.sender)) recvaddr = utils.sha3(rlp.encode([sender, nonce]))[12:] msg.to = recvaddr block.increment_nonce(msg.sender) # Transfer value, instaquit if not enough block.delta_balance(recvaddr, msg.value) o = block.delta_balance(msg.sender, msg.value) if not o: return 0, msg.gas compustate = Compustate(gas=msg.gas) # Main loop while 1: o = apply_op(block, tx, msg, msg.data, compustate) if o is not None: if o == OUT_OF_GAS: block.revert(snapshot) return 0, 0, [] else: block.set_code(recvaddr, ''.join(map(chr, o))) return recvaddr, compustate.gas, o
def encode_function_call(self, function_name, args): """ Return the encoded function call. Args: function_name (str): One of the existing functions described in the contract interface. args (List[object]): The function arguments that wll be encoded and used in the contract execution in the vm. Return: bin: The encoded function name and arguments so that it can be used with the evm to execute a funcion call, the binary string follows the Ethereum Contract ABI. """ if function_name not in self.function_data: raise ValueError('Unkown function {}'.format(function_name)) description = self.function_data[function_name] function_selector = zpad(encode_int(description['prefix']), 4) arguments = encode_abi(description['encode_types'], args) return function_selector + arguments