<s> import sys <EOL> import rlp <EOL> from . base import LockSet , Vote , VoteBlock , VoteNil , Signed , Ready <EOL> from . base import BlockProposal , VotingInstruction , DoubleVotingError , InvalidVoteError <EOL> from . base import Block , Proposal , HDCBlockHeader , InvalidProposalError <EOL> from . protocol import HDCProtocol <EOL> from . utils import cstr , phx <EOL> from . synchronizer import Synchronizer <EOL> from ethereum . slogging import get_logger <EOL> log = get_logger ( '<STR_LIT>' ) <EOL> class ManagerDict ( object ) : <EOL> def __init__ ( self , dklass , parent ) : <EOL> self . d = dict ( ) <EOL> self . dklass = dklass <EOL> self . parent = parent <EOL> def __getitem__ ( self , k ) : <EOL> if k not in self . d : <EOL> self . d [ k ] = self . dklass ( self . parent , k ) <EOL> return self . d [ k ] <EOL> def __iter__ ( self ) : <EOL> return iter ( sorted ( self . d , reverse = True ) ) <EOL> def pop ( self , k ) : <EOL> self . d . pop ( k ) <EOL> class MissingParent ( Exception ) : <EOL> pass <EOL> class ProtocolFailureEvidence ( object ) : <EOL> protocol = None <EOL> evidence = None <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . __class__ . __name__ , <EOL> self . protocol , self . evidence ) <EOL> class InvalidProposalEvidence ( ProtocolFailureEvidence ) : <EOL> def __init__ ( self , protocol , proposal ) : <EOL> self . protocol = protocol <EOL> self . evidence = proposal <EOL> class DoubleVotingEvidence ( ProtocolFailureEvidence ) : <EOL> def __init__ ( self , protocol , vote , othervote ) : <EOL> self . protocol = protocol <EOL> self . evidence = ( vote , othervote ) <EOL> class InvalidVoteEvidence ( ProtocolFailureEvidence ) : <EOL> def __init__ ( self , protocol , vote ) : <EOL> self . protocol = protocol <EOL> self . evidence = vote <EOL> class FailedToProposeEvidence ( ProtocolFailureEvidence ) : <EOL> def __init__ ( self , protocol , round_lockset ) : <EOL> self . protocol = protocol <EOL> self . evidence = round_lockset <EOL> class ForkDetectedEvidence ( ProtocolFailureEvidence ) : <EOL> def __init__ ( self , protocol , prevblock , block , committing_lockset ) : <EOL> self . protocol = protocol <EOL> self . evidence = ( prevblock , block , committing_lockset ) <EOL> class ConsensusManager ( object ) : <EOL> allow_empty_blocks = False <EOL> num_initial_blocks = <NUM_LIT:10> <EOL> round_timeout = <NUM_LIT:3> <EOL> round_timeout_factor = <NUM_LIT> <EOL> transaction_timeout = <NUM_LIT:0.5> <EOL> def __init__ ( self , chainservice , consensus_contract , privkey ) : <EOL> self . chainservice = chainservice <EOL> self . chain = chainservice . chain <EOL> self . contract = consensus_contract <EOL> self . privkey = privkey <EOL> self . synchronizer = Synchronizer ( self ) <EOL> self . heights = ManagerDict ( HeightManager , self ) <EOL> self . block_candidates = dict ( ) <EOL> self . tracked_protocol_failures = list ( ) <EOL> self . ready_validators = set ( ) <EOL> self . ready_nonce = <NUM_LIT:0> <EOL> assert self . contract . isvalidator ( self . coinbase ) <EOL> self . initialize_locksets ( ) <EOL> self . ready_validators = set ( [ self . coinbase ] ) <EOL> def initialize_locksets ( self ) : <EOL> log . debug ( '<STR_LIT>' ) <EOL> v = self . sign ( VoteBlock ( <NUM_LIT:0> , <NUM_LIT:0> , self . chainservice . chain . genesis . hash ) ) <EOL> self . add_vote ( v ) <EOL> head_proposal = self . load_proposal ( self . head . hash ) <EOL> if head_proposal : <EOL> assert head_proposal . blockhash == self . head . hash <EOL> for v in head_proposal . signing_lockset : <EOL> self . add_vote ( v ) <EOL> assert self . heights [ self . head . header . number - <NUM_LIT:1> ] . has_quorum <EOL> last_committing_lockset = self . load_last_committing_lockset ( ) <EOL> if last_committing_lockset : <EOL> assert last_committing_lockset . has_quorum == self . head . hash <EOL> for v in last_committing_lockset . votes : <EOL> self . add_vote ( v ) <EOL> assert self . heights [ self . head . header . number ] . has_quorum <EOL> else : <EOL> assert self . head . header . number == <NUM_LIT:0> <EOL> assert self . highest_committing_lockset <EOL> assert self . last_committing_lockset <EOL> assert self . last_valid_lockset <EOL> def store_last_committing_lockset ( self , ls ) : <EOL> assert isinstance ( ls , LockSet ) <EOL> assert ls . has_quorum <EOL> self . chainservice . db . put ( '<STR_LIT>' , rlp . encode ( ls ) ) <EOL> def load_last_committing_lockset ( self ) : <EOL> try : <EOL> data = self . chainservice . db . get ( '<STR_LIT>' ) <EOL> except KeyError : <EOL> self . log ( '<STR_LIT>' ) <EOL> return <EOL> return rlp . decode ( data , sedes = LockSet ) <EOL> def store_proposal ( self , p ) : <EOL> assert isinstance ( p , BlockProposal ) <EOL> self . chainservice . db . put ( '<STR_LIT>' % p . blockhash , rlp . encode ( p ) ) <EOL> def load_proposal_rlp ( self , blockhash ) : <EOL> try : <EOL> prlp = self . chainservice . db . get ( '<STR_LIT>' % blockhash ) <EOL> assert isinstance ( prlp , bytes ) <EOL> return prlp <EOL> except KeyError : <EOL> return None <EOL> def load_proposal ( self , blockhash ) : <EOL> prlp = self . load_proposal_rlp ( blockhash ) <EOL> if prlp : <EOL> return rlp . decode ( prlp , sedes = BlockProposal ) <EOL> def get_blockproposal ( self , blockhash ) : <EOL> return self . block_candidates . get ( blockhash ) or self . load_proposal ( blockhash ) <EOL> def has_blockproposal ( self , blockhash ) : <EOL> return bool ( self . load_proposal_rlp ( blockhash ) ) <EOL> def get_blockproposal_rlp_by_height ( self , height ) : <EOL> assert <NUM_LIT:0> < height < self . height <EOL> bh = self . chainservice . chain . index . get_block_by_number ( height ) <EOL> return self . load_proposal_rlp ( bh ) <EOL> @ property <EOL> def coinbase ( self ) : <EOL> return self . chain . coinbase <EOL> def set_proposal_lock ( self , block ) : <EOL> self . chainservice . set_proposal_lock ( block ) <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( phx ( self . coinbase ) , self . height , self . round , <EOL> self . active_round . lock , <EOL> self . active_round . lockset . state ) <EOL> def log ( self , tag , ** kargs ) : <EOL> t = int ( self . chainservice . now ) <EOL> c = lambda x : cstr ( self . coinbase , x ) <EOL> msg = '<STR_LIT:U+0020>' . join ( [ str ( t ) , c ( repr ( self ) ) , tag , ( '<STR_LIT>' % kargs if kargs else '<STR_LIT>' ) ] ) <EOL> log . debug ( msg ) <EOL> @ property <EOL> def head ( self ) : <EOL> return self . chain . head <EOL> @ property <EOL> def height ( self ) : <EOL> return self . head . number + <NUM_LIT:1> <EOL> @ property <EOL> def round ( self ) : <EOL> return self . heights [ self . height ] . round <EOL> def broadcast ( self , m ) : <EOL> self . log ( '<STR_LIT>' , message = m ) <EOL> self . chainservice . broadcast ( m ) <EOL> @ property <EOL> def is_ready ( self ) : <EOL> return len ( self . ready_validators ) > len ( self . contract . validators ) * <NUM_LIT:2> / <NUM_LIT> <EOL> def send_ready ( self ) : <EOL> self . log ( '<STR_LIT>' ) <EOL> assert not self . is_ready <EOL> r = Ready ( self . ready_nonce , self . active_round . lockset ) <EOL> self . sign ( r ) <EOL> self . broadcast ( r ) <EOL> self . ready_nonce += <NUM_LIT:1> <EOL> def add_ready ( self , ready , proto = None ) : <EOL> assert isinstance ( ready , Ready ) <EOL> assert self . contract . isvalidator ( ready . sender ) <EOL> self . ready_validators . add ( ready . sender ) <EOL> self . log ( '<STR_LIT>' , validator = ready . sender ) <EOL> if self . is_ready : <EOL> self . log ( '<STR_LIT>' , <EOL> num = len ( self . ready_validators ) ) <EOL> else : <EOL> self . send_ready ( ) <EOL> def add_vote ( self , v , proto = None ) : <EOL> assert isinstance ( v , Vote ) <EOL> assert self . contract . isvalidator ( v . sender ) <EOL> self . ready_validators . add ( v . sender ) <EOL> is_own_vote = bool ( v . sender == self . coinbase ) <EOL> try : <EOL> success = self . heights [ v . height ] . add_vote ( v , force_replace = is_own_vote ) <EOL> except DoubleVotingError : <EOL> ls = self . heights [ v . height ] . rounds [ v . round ] . lockset <EOL> self . tracked_protocol_failures . append ( DoubleVotingEvidence ( proto , v , ls ) ) <EOL> log . warn ( '<STR_LIT>' , vote = v , ls = ls ) <EOL> return success <EOL> def add_proposal ( self , p , proto = None ) : <EOL> assert isinstance ( p , Proposal ) <EOL> assert proto is None or isinstance ( proto , HDCProtocol ) <EOL> def check ( valid ) : <EOL> if not valid : <EOL> self . tracked_protocol_failures . append ( InvalidProposalEvidence ( None , p ) ) <EOL> log . warn ( '<STR_LIT>' , p = p ) <EOL> raise InvalidProposalError ( ) <EOL> return True <EOL> self . log ( '<STR_LIT>' , p = p ) <EOL> if p . height < self . height : <EOL> self . log ( '<STR_LIT>' ) <EOL> return <EOL> if not check ( self . contract . isvalidator ( p . sender ) and self . contract . isproposer ( p ) ) : <EOL> return <EOL> self . ready_validators . add ( p . sender ) <EOL> if not check ( p . lockset . is_valid ) : <EOL> return <EOL> if not check ( p . lockset . height == p . height or p . round == <NUM_LIT:0> ) : <EOL> return <EOL> if not check ( p . round - p . lockset . round == <NUM_LIT:1> or p . round == <NUM_LIT:0> ) : <EOL> return <EOL> if proto is not None : <EOL> self . synchronizer . on_proposal ( p , proto ) <EOL> for v in p . lockset : <EOL> self . add_vote ( v ) <EOL> if isinstance ( p , BlockProposal ) : <EOL> if not check ( p . block . number == p . height ) : <EOL> return <EOL> if not check ( p . lockset . has_noquorum or p . round == <NUM_LIT:0> ) : <EOL> return <EOL> if p . height > self . height : <EOL> self . log ( '<STR_LIT>' , p = p ) <EOL> return <EOL> blk = self . chainservice . link_block ( p . block ) <EOL> if not check ( blk ) : <EOL> ls = self . heights [ p . height ] . last_quorum_lockset <EOL> if ls and ls . has_quorum == p . blockhash : <EOL> raise ForkDetectedEvidence ( proto , ( self . head , p , ls ) ) <EOL> sys . exit ( <NUM_LIT:1> ) <EOL> return <EOL> p . _mutable = True <EOL> p . _cached_rlp = None <EOL> p . block = blk <EOL> self . log ( '<STR_LIT>' ) <EOL> self . add_block_proposal ( p ) <EOL> else : <EOL> assert isinstance ( p , VotingInstruction ) <EOL> assert p . lockset . round == p . round - <NUM_LIT:1> and p . height == p . lockset . height <EOL> assert p . round > <NUM_LIT:0> <EOL> assert p . lockset . has_quorum_possible <EOL> assert not p . lockset . has_quorum <EOL> if not check ( p . lockset . has_quorum_possible and not p . lockset . has_quorum ) : <EOL> return <EOL> is_valid = self . heights [ p . height ] . add_proposal ( p ) <EOL> return is_valid <EOL> def add_lockset ( self , ls , proto = None ) : <EOL> assert ls . is_valid <EOL> for v in ls : <EOL> self . add_vote ( v ) <EOL> def add_block_proposal ( self , p ) : <EOL> assert isinstance ( p , BlockProposal ) <EOL> if self . has_blockproposal ( p . blockhash ) : <EOL> self . log ( '<STR_LIT>' ) <EOL> return <EOL> assert p . signing_lockset . has_quorum <EOL> assert p . signing_lockset . height == p . height - <NUM_LIT:1> <EOL> for v in p . signing_lockset : <EOL> self . add_vote ( v ) <EOL> self . block_candidates [ p . blockhash ] = p <EOL> @ property <EOL> def last_committing_lockset ( self ) : <EOL> return self . heights [ self . height - <NUM_LIT:1> ] . last_quorum_lockset <EOL> @ property <EOL> def highest_committing_lockset ( self ) : <EOL> for height in self . heights : <EOL> ls = self . heights [ height ] . last_quorum_lockset <EOL> if ls : <EOL> return ls <EOL> @ property <EOL> def last_valid_lockset ( self ) : <EOL> return self . heights [ self . height ] . last_valid_lockset or self . last_committing_lockset <EOL> @ property <EOL> def last_lock ( self ) : <EOL> return self . heights [ self . height ] . last_lock <EOL> @ property <EOL> def last_blockproposal ( self ) : <EOL> p = self . heights [ self . height ] . last_voted_blockproposal <EOL> if p : <EOL> return p <EOL> elif self . height > <NUM_LIT:1> : <EOL> return self . get_blockproposal ( self . head . hash ) <EOL> @ property <EOL> def active_round ( self ) : <EOL> hm = self . heights [ self . height ] <EOL> return hm . rounds [ hm . round ] <EOL> def setup_alarm ( self ) : <EOL> ar = self . active_round <EOL> delay = ar . get_timeout ( ) <EOL> self . log ( '<STR_LIT>' , delay = delay ) <EOL> if self . is_waiting_for_proposal : <EOL> if delay is not None : <EOL> self . chainservice . setup_alarm ( delay , self . on_alarm , ar ) <EOL> self . log ( '<STR_LIT>' , now = self . chainservice . now , <EOL> delay = delay , triggered = delay + self . chainservice . now ) <EOL> else : <EOL> self . chainservice . setup_transaction_alarm ( self . on_alarm , ar ) <EOL> self . log ( '<STR_LIT>' , now = self . chainservice . now ) <EOL> def on_alarm ( self , ar ) : <EOL> assert isinstance ( ar , RoundManager ) <EOL> if self . active_round == ar : <EOL> self . log ( '<STR_LIT>' , ts = self . chainservice . now ) <EOL> if not self . is_ready : <EOL> self . log ( '<STR_LIT>' , ts = self . chainservice . now ) <EOL> self . setup_alarm ( ) <EOL> elif not self . is_waiting_for_proposal : <EOL> self . log ( '<STR_LIT>' , ts = self . chainservice . now ) <EOL> self . setup_alarm ( ) <EOL> else : <EOL> self . process ( ) <EOL> @ property <EOL> def is_waiting_for_proposal ( self ) : <EOL> return self . allow_empty_blocks or self . has_pending_transactions or self . height <= self . num_initial_blocks <EOL> @ property <EOL> def has_pending_transactions ( self ) : <EOL> return self . chain . head_candidate . num_transactions ( ) > <NUM_LIT:0> <EOL> def process ( self ) : <EOL> r = self . _process ( ) <EOL> return r <EOL> def _process ( self ) : <EOL> self . log ( '<STR_LIT:->' * <NUM_LIT> ) <EOL> self . log ( '<STR_LIT>' ) <EOL> if not self . is_ready : <EOL> self . log ( '<STR_LIT>' ) <EOL> self . setup_alarm ( ) <EOL> return <EOL> self . commit ( ) <EOL> self . heights [ self . height ] . process ( ) <EOL> if self . commit ( ) : <EOL> return self . _process ( ) <EOL> self . cleanup ( ) <EOL> self . synchronizer . process ( ) <EOL> self . setup_alarm ( ) <EOL> for f in self . tracked_protocol_failures : <EOL> if not isinstance ( f , FailedToProposeEvidence ) : <EOL> log . warn ( '<STR_LIT>' , incident = f ) <EOL> start = process <EOL> def commit ( self ) : <EOL> self . log ( '<STR_LIT>' ) <EOL> for p in [ c for c in self . block_candidates . values ( ) if c . block . prevhash == self . head . hash ] : <EOL> assert isinstance ( p , BlockProposal ) <EOL> ls = self . heights [ p . height ] . last_quorum_lockset <EOL> if ls and ls . has_quorum == p . blockhash : <EOL> self . store_proposal ( p ) <EOL> self . store_last_committing_lockset ( ls ) <EOL> success = self . chainservice . commit_block ( p . block ) <EOL> assert success <EOL> if success : <EOL> self . log ( '<STR_LIT>' , p = p , hash = phx ( p . blockhash ) ) <EOL> assert self . head == p . block <EOL> self . commit ( ) <EOL> return True <EOL> else : <EOL> self . log ( '<STR_LIT>' , p = p ) <EOL> else : <EOL> self . log ( '<STR_LIT>' , p = p ) <EOL> if ls : <EOL> self . log ( '<STR_LIT>' , votes = ls . votes ) <EOL> def cleanup ( self ) : <EOL> self . log ( '<STR_LIT>' ) <EOL> for p in self . block_candidates . values ( ) : <EOL> if self . head . number >= p . height : <EOL> self . block_candidates . pop ( p . blockhash ) <EOL> for h in list ( self . heights ) : <EOL> if self . heights [ h ] . height < self . head . number : <EOL> self . heights . pop ( h ) <EOL> def mk_lockset ( self , height ) : <EOL> return LockSet ( num_eligible_votes = self . contract . num_eligible_votes ( height ) ) <EOL> def sign ( self , o ) : <EOL> assert isinstance ( o , Signed ) <EOL> return o . sign ( self . privkey ) <EOL> class HeightManager ( object ) : <EOL> def __init__ ( self , consensusmanager , height = <NUM_LIT:0> ) : <EOL> self . cm = consensusmanager <EOL> self . log = self . cm . log <EOL> self . height = height <EOL> self . rounds = ManagerDict ( RoundManager , self ) <EOL> log . debug ( '<STR_LIT>' % ( phx ( self . cm . coinbase ) , self . height ) ) <EOL> @ property <EOL> def round ( self ) : <EOL> l = self . last_valid_lockset <EOL> if l : <EOL> return l . round + <NUM_LIT:1> <EOL> return <NUM_LIT:0> <EOL> @ property <EOL> def last_lock ( self ) : <EOL> "<STR_LIT>" <EOL> rs = list ( self . rounds ) <EOL> assert len ( rs ) < <NUM_LIT:2> or rs [ <NUM_LIT:0> ] > rs [ <NUM_LIT:1> ] <EOL> for r in self . rounds : <EOL> if self . rounds [ r ] . lock is not None : <EOL> return self . rounds [ r ] . lock <EOL> @ property <EOL> def last_voted_blockproposal ( self ) : <EOL> "<STR_LIT>" <EOL> for r in self . rounds : <EOL> if isinstance ( self . rounds [ r ] . proposal , BlockProposal ) : <EOL> assert isinstance ( self . rounds [ r ] . lock , Vote ) <EOL> if self . rounds [ r ] . proposal . blockhash == self . rounds [ r ] . lock . blockhash : <EOL> return self . rounds [ r ] . proposal <EOL> @ property <EOL> def last_valid_lockset ( self ) : <EOL> "<STR_LIT>" <EOL> for r in self . rounds : <EOL> ls = self . rounds [ r ] . lockset <EOL> if ls . is_valid : <EOL> return ls <EOL> return None <EOL> @ property <EOL> def last_quorum_lockset ( self ) : <EOL> found = None <EOL> for r in sorted ( self . rounds ) : <EOL> ls = self . rounds [ r ] . lockset <EOL> if ls . is_valid and ls . has_quorum : <EOL> if found is not None : <EOL> for r in sorted ( self . rounds ) : <EOL> self . log ( '<STR_LIT>' , round = r , ls = self . rounds [ r ] . lockset , <EOL> votes = self . rounds [ r ] . lockset . votes ) <EOL> if found . has_quorum != ls . has_quorum : <EOL> log . error ( '<STR_LIT>' ) <EOL> import sys <EOL> sys . exit ( <NUM_LIT:1> ) <EOL> found = ls <EOL> return found <EOL> @ property <EOL> def has_quorum ( self ) : <EOL> ls = self . last_quorum_lockset <EOL> if ls : <EOL> return ls . has_quorum <EOL> def add_vote ( self , v , force_replace = False ) : <EOL> return self . rounds [ v . round ] . add_vote ( v , force_replace ) <EOL> def add_proposal ( self , p ) : <EOL> assert p . height == self . height <EOL> assert p . lockset . is_valid <EOL> if p . round > self . round : <EOL> self . round = p . round <EOL> return self . rounds [ p . round ] . add_proposal ( p ) <EOL> def process ( self ) : <EOL> self . log ( '<STR_LIT>' , height = self . height ) <EOL> self . rounds [ self . round ] . process ( ) <EOL> class RoundManager ( object ) : <EOL> def __init__ ( self , heightmanager , round_ = <NUM_LIT:0> ) : <EOL> assert isinstance ( round_ , int ) <EOL> self . round = round_ <EOL> self . hm = heightmanager <EOL> self . cm = heightmanager . cm <EOL> self . log = self . hm . log <EOL> self . height = heightmanager . height <EOL> self . lockset = self . cm . mk_lockset ( self . height ) <EOL> self . proposal = None <EOL> self . lock = None <EOL> self . timeout_time = None <EOL> log . debug ( '<STR_LIT>' % <EOL> ( phx ( self . cm . coinbase ) , self . hm . height , self . round ) ) <EOL> def get_timeout ( self ) : <EOL> "<STR_LIT>" <EOL> if self . timeout_time is not None or self . proposal : <EOL> return <EOL> now = self . cm . chainservice . now <EOL> round_timeout = ConsensusManager . round_timeout <EOL> round_timeout_factor = ConsensusManager . round_timeout_factor <EOL> delay = round_timeout * round_timeout_factor ** self . round <EOL> self . timeout_time = now + delay <EOL> return delay <EOL> def add_vote ( self , v , force_replace = False ) : <EOL> if v in self . lockset : <EOL> return <EOL> self . log ( '<STR_LIT>' , vote = v , received_proposal = self . proposal ) <EOL> try : <EOL> success = self . lockset . add ( v , force_replace ) <EOL> except InvalidVoteError : <EOL> self . cm . tracked_protocol_failures . append ( InvalidVoteEvidence ( None , v ) ) <EOL> return <EOL> if self . lockset . is_valid : <EOL> self . log ( '<STR_LIT>' , ls = self . lockset ) <EOL> if not self . proposal and self . lockset . has_noquorum : <EOL> self . cm . tracked_protocol_failures . append ( <EOL> FailedToProposeEvidence ( None , self . lockset ) ) <EOL> return success <EOL> def add_proposal ( self , p ) : <EOL> self . log ( '<STR_LIT>' , proposal = p , old = self . proposal ) <EOL> assert isinstance ( p , Proposal ) <EOL> assert isinstance ( p , VotingInstruction ) or isinstance ( p . block , Block ) <EOL> assert not self . proposal or self . proposal == p <EOL> self . proposal = p <EOL> return True <EOL> def process ( self ) : <EOL> self . log ( '<STR_LIT>' , height = self . hm . height , round = self . round ) <EOL> assert self . cm . round == self . round <EOL> assert self . cm . height == self . hm . height == self . height <EOL> p = self . propose ( ) <EOL> if isinstance ( p , BlockProposal ) : <EOL> self . cm . add_block_proposal ( p ) <EOL> if p : <EOL> self . cm . broadcast ( p ) <EOL> v = self . vote ( ) <EOL> if v : <EOL> self . cm . broadcast ( v ) <EOL> assert not self . proposal or self . lock <EOL> def mk_proposal ( self , round_lockset = None ) : <EOL> signing_lockset = self . cm . last_committing_lockset . copy ( ) <EOL> if self . round > <NUM_LIT:0> : <EOL> round_lockset = self . cm . last_valid_lockset . copy ( ) <EOL> assert round_lockset . has_noquorum <EOL> else : <EOL> round_lockset = None <EOL> assert signing_lockset . has_quorum <EOL> assert round_lockset is None or self . round > <NUM_LIT:0> <EOL> block = self . cm . chain . head_candidate <EOL> block . header . __class__ = HDCBlockHeader <EOL> block . should_be_locked = True <EOL> bp = BlockProposal ( self . height , self . round , block , signing_lockset , round_lockset ) <EOL> self . cm . sign ( bp ) <EOL> self . cm . set_proposal_lock ( block ) <EOL> assert self . cm . chainservice . proposal_lock . locked ( ) <EOL> return bp <EOL> def propose ( self ) : <EOL> if not self . cm . is_waiting_for_proposal : <EOL> return <EOL> proposer = self . cm . contract . proposer ( self . height , self . round ) <EOL> self . log ( '<STR_LIT>' , proposer = phx ( proposer ) , proposal = self . proposal , lock = self . lock ) <EOL> if proposer != self . cm . coinbase : <EOL> return <EOL> self . log ( '<STR_LIT>' ) <EOL> if self . proposal : <EOL> assert self . proposal . sender == self . cm . coinbase <EOL> assert self . lock <EOL> return <EOL> round_lockset = self . cm . last_valid_lockset <EOL> if not round_lockset : <EOL> self . log ( '<STR_LIT>' ) <EOL> return <EOL> self . log ( '<STR_LIT>' , round_lockset = round_lockset ) <EOL> if round_lockset . height == self . height and round_lockset . has_quorum : <EOL> self . log ( '<STR_LIT>' ) <EOL> return <EOL> elif self . round == <NUM_LIT:0> or round_lockset . has_noquorum : <EOL> proposal = self . mk_proposal ( ) <EOL> elif round_lockset . has_quorum_possible : <EOL> proposal = VotingInstruction ( self . height , self . round , round_lockset . copy ( ) ) <EOL> self . cm . sign ( proposal ) <EOL> else : <EOL> raise Exception ( '<STR_LIT>' ) <EOL> self . log ( '<STR_LIT>' , p = proposal , bh = phx ( proposal . blockhash ) ) <EOL> self . proposal = proposal <EOL> return proposal <EOL> def vote ( self ) : <EOL> if self . lock : <EOL> return <EOL> self . log ( '<STR_LIT>' , proposal = self . proposal , pid = id ( self . proposal ) ) <EOL> last_lock = self . hm . last_lock <EOL> if self . proposal : <EOL> if isinstance ( self . proposal , VotingInstruction ) : <EOL> assert self . proposal . lockset . has_quorum_possible <EOL> self . log ( '<STR_LIT>' ) <EOL> v = VoteBlock ( self . height , self . round , self . proposal . blockhash ) <EOL> elif not isinstance ( last_lock , VoteBlock ) : <EOL> assert isinstance ( self . proposal , BlockProposal ) <EOL> assert isinstance ( self . proposal . block , Block ) <EOL> assert self . proposal . lockset . has_noquorum or self . round == <NUM_LIT:0> <EOL> assert self . proposal . block . prevhash == self . cm . head . hash <EOL> self . log ( '<STR_LIT>' ) <EOL> v = VoteBlock ( self . height , self . round , self . proposal . blockhash ) <EOL> else : <EOL> self . log ( '<STR_LIT>' ) <EOL> v = VoteBlock ( self . height , self . round , last_lock . blockhash ) <EOL> elif self . timeout_time is not None and self . cm . chainservice . now >= self . timeout_time : <EOL> if isinstance ( last_lock , VoteBlock ) : <EOL> self . log ( '<STR_LIT>' ) <EOL> v = VoteBlock ( self . height , self . round , last_lock . blockhash ) <EOL> else : <EOL> self . log ( '<STR_LIT>' ) <EOL> v = VoteNil ( self . height , self . round ) <EOL> else : <EOL> return <EOL> self . cm . sign ( v ) <EOL> self . log ( '<STR_LIT>' , vote = v ) <EOL> self . lock = v <EOL> assert self . hm . last_lock == self . lock <EOL> self . lockset . add ( v ) <EOL> return v </s>
