go-ethereum/blocks.py

101 lines
3.5 KiB
Python
Raw Normal View History

2013-12-19 12:38:09 -06:00
from pybitcointools import *
import rlp
import re
from transactions import Transaction
from trie import Trie
import sys
2013-12-19 12:38:09 -06:00
class Block():
def __init__(self,data=None):
2013-12-19 12:38:09 -06:00
if not data:
return
2013-12-19 12:38:09 -06:00
if re.match('^[0-9a-fA-F]*$',data):
data = data.decode('hex')
2013-12-25 07:26:43 -06:00
header, transaction_list, self.uncles = rlp.decode(data)
[ self.number,
self.prevhash,
2013-12-25 07:26:43 -06:00
self.uncles_root,
self.coinbase,
state_root,
self.transactions_root,
self.difficulty,
self.timestamp,
self.nonce,
self.extra ] = header
self.transactions = [Transaction(x) for x in transaction_list]
self.state = Trie('statedb',state_root)
self.reward = 0
2013-12-19 12:38:09 -06:00
# Verifications
if self.state.root != '' and self.state.db.get(self.state.root) == '':
raise Exception("State Merkle root not found in database!")
if bin_sha256(rlp.encode(transaction_list)) != self.transactions_root:
2013-12-19 12:38:09 -06:00
raise Exception("Transaction list root hash does not match!")
if bin_sha256(rlp.encode(self.uncles)) != self.uncles_root:
2013-12-25 07:26:43 -06:00
raise Exception("Uncle root hash does not match!")
# TODO: check POW
2013-12-19 12:38:09 -06:00
def pay_fee(self,address,fee,tominer=True):
# Subtract fee from sender
sender_state = rlp.decode(self.state.get(address))
if not sender_state or sender_state[1] < fee:
return False
sender_state[1] -= fee
self.state.update(address,sender_state)
# Pay fee to miner
if tominer:
miner_state = rlp.decode(self.state.get(self.coinbase)) or [0,0,0]
miner_state[1] += fee
self.state.update(self.coinbase,miner_state)
return True
2013-12-19 12:38:09 -06:00
def get_nonce(self,address):
state = rlp.decode(self.state.get(address))
if not state or state[0] == 0: return False
return state[2]
2013-12-19 12:38:09 -06:00
def get_balance(self,address):
state = rlp.decode(self.state.get(address))
return state[1] if state else 0
def set_balance(self,address,balance):
state = rlp.decode(self.state.get(address)) or [0,0,0]
state[1] = balance
self.state.update(address,rlp.encode(state))
2013-12-19 12:38:09 -06:00
# Making updates to the object obtained from this method will do nothing. You need
# to call update_contract to finalize the changes.
def get_contract(self,address):
state = rlp.decode(self.state.get(address))
if not state or state[0] == 0: return False
return Trie('statedb',state[2])
2013-12-19 12:38:09 -06:00
def update_contract(self,address,contract):
state = rlp.decode(self.state.get(address)) or [1,0,'']
if state[0] == 0: return False
state[2] = contract.root
self.state.update(address,state)
2013-12-19 12:38:09 -06:00
# Serialization method; should act as perfect inverse function of the constructor
# assuming no verification failures
2013-12-19 12:38:09 -06:00
def serialize(self):
txlist = [x.serialize() for x in self.transactions]
header = [ self.number,
self.prevhash,
2013-12-25 07:26:43 -06:00
bin_sha256(rlp.encode(self.uncles)),
self.coinbase,
self.state.root,
bin_sha256(rlp.encode(txlist)),
self.difficulty,
self.timestamp,
self.nonce,
self.extra ]
2013-12-25 07:26:43 -06:00
return rlp.encode([header, txlist, self.uncles ])
def hash(self):
return bin_sha256(self.serialize())