示例#1
0
 def mk_ls(h, r):
     ls = LockSet()
     votes = [
         Locked(Signature(i, h, r), '0' * 32)
         for i in range(ls.eligible_votes)
     ]
     for i, v in enumerate(votes):
         ls.add(v)
     return ls
示例#2
0
def test_LockSet_isvalid():
    ls = LockSet()
    votes = [Locked(Signature(i, 2, 3), '0'*32) for i in range(ls.eligible_votes)]
    for i, v in enumerate(votes):
        ls.add(v)
        assert len(ls) == i + 1
        if len(ls) < ls.eligible_votes * 2/3.:
            assert not ls.is_valid
        else:
            assert ls.is_valid
            assert ls.has_quorum  # same blockhash
示例#3
0
 def __init__(self, heightmanager, round=0):
     self.hm = heightmanager
     self.cm = heightmanager.cm
     self.log = self.hm.log
     assert isinstance(round, int)
     self.round = round
     self.height = heightmanager.height
     self.lockset = LockSet()
     self.proposal = None
     self.lock = None
     self.timeout_time = None
     print('A:%d Created RoundManager H:%d R:%d' %
           (self.cm.coinbase, self.hm.height, self.round))
示例#4
0
def test_LockSet_isvalid():
    ls = LockSet()
    votes = [
        Locked(Signature(i, 2, 3), '0' * 32) for i in range(ls.eligible_votes)
    ]
    for i, v in enumerate(votes):
        ls.add(v)
        assert len(ls) == i + 1
        if len(ls) < ls.eligible_votes * 2 / 3.:
            assert not ls.is_valid
        else:
            assert ls.is_valid
            assert ls.has_quorum  # same blockhash
示例#5
0
def test_LockSet():
    ls = LockSet()
    assert not ls
    assert len(ls) == 0
    v1 = Locked(Signature(1, 2, 3), '0' * 32)
    v2 = Locked(Signature(1, 2, 3), '0' * 32)
    ls.add(v1)
    assert ls
    assert len(ls) == 1
    lsh = ls.hash
    ls.add(v1)
    assert lsh == ls.hash
    assert len(ls) == 1
    ls.add(v2)
    assert lsh == ls.hash
    assert len(ls) == 1
示例#6
0
def test_BlockProposal():
    ls = LockSet()
    for i in range(10):
        s = Signature(i, 2, 3)
        ls.add(Locked(s, '0' * 32))

    bls = LockSet()
    for i in range(10):
        s = Signature(i, 1, 2)
        bls.add(Locked(s, '0' * 32))

    assert len(ls) == 10
    assert ls.has_quorum
    block = Block(1, 2, 4, '0' * 32, bls)
    p = BlockProposal(Signature(1, 2, 4), ls, block)
    p2 = BlockProposal(Signature(1, 2, 4), ls, block)
    assert p == p2
示例#7
0
def test_LockSet():
    ls = LockSet()
    assert not ls
    assert len(ls) == 0
    v1 = Locked(Signature(1, 2, 3), '0'*32)
    v2 = Locked(Signature(1, 2, 3), '0'*32)
    ls.add(v1)
    assert ls
    assert len(ls) == 1
    lsh = ls.hash
    ls.add(v1)
    assert lsh == ls.hash
    assert len(ls) == 1
    ls.add(v2)
    assert lsh == ls.hash
    assert len(ls) == 1
示例#8
0
def test_BlockProposal():
    ls = LockSet()
    for i in range(10):
        s = Signature(i, 2, 3)
        ls.add(Locked(s, '0'*32))

    bls = LockSet()
    for i in range(10):
        s = Signature(i, 1, 2)
        bls.add(Locked(s, '0'*32))

    assert len(ls) == 10
    assert ls.has_quorum
    block = Block(1, 2, 4, '0'*32, bls)
    p = BlockProposal(Signature(1, 2, 4), ls, block)
    p2 = BlockProposal(Signature(1, 2, 4), ls, block)
    assert p == p2
示例#9
0
def test_LockSet_quorums():
    combinations = dict(has_quorum=[
                                [1]*7,
                                [1]*7 + [2]*3,
                                [1]*7 + [None]*3,
                                ],
                        has_noquorum=[
                                [1]*3 + [2]*3 + [None],
                                [None] * 7,
                                [None] * 10,
                                range(10),
                                range(7)
                                ],
                        has_quorum_possible=[
                                [1] * 4 + [None]*3,
                                [1] * 4 + [2]*4,
                                [1] * 4 + [2]*3 + [3]*3,
                                [1] * 6 + [2]
                            ])

    r, h = 1, 2
    hash_ = lambda v: sha3(str(v))

    for method, permutations in combinations.items():
        for set_ in permutations:
            assert len(set_) >= 7
            ls = LockSet()
            for address, p in enumerate(set_):
                if p is not None:
                    ls.add(Locked(Signature(address, h, r), hash_(p)))
                else:
                    ls.add(NotLocked(Signature(address, h, r)))
            assert len(ls) >= 7
            assert getattr(ls, method)

            # check stable sort
            bhs = ls.blockhashes()
            if len(bhs) > 1:
                assert ishash(bhs[0][0])
                assert isinstance(bhs[0][1], int)
                if bhs[0][1] == bhs[1][1]:
                    assert bhs[0][0] > bhs[1][0]
                else:
                    assert bhs[0][1] > bhs[1][1]
示例#10
0
def test_LockSet_quorums():
    combinations = dict(has_quorum=[
        [1] * 7,
        [1] * 7 + [2] * 3,
        [1] * 7 + [None] * 3,
    ],
                        has_noquorum=[[1] * 3 + [2] * 3 + [None], [None] * 7,
                                      [None] * 10,
                                      range(10),
                                      range(7)],
                        has_quorum_possible=[[1] * 4 + [None] * 3,
                                             [1] * 4 + [2] * 4,
                                             [1] * 4 + [2] * 3 + [3] * 3,
                                             [1] * 6 + [2]])

    r, h = 1, 2
    hash_ = lambda v: sha3(str(v))

    for method, permutations in combinations.items():
        for set_ in permutations:
            assert len(set_) >= 7
            ls = LockSet()
            for address, p in enumerate(set_):
                if p is not None:
                    ls.add(Locked(Signature(address, h, r), hash_(p)))
                else:
                    ls.add(NotLocked(Signature(address, h, r)))
            assert len(ls) >= 7
            assert getattr(ls, method)

            # check stable sort
            bhs = ls.blockhashes()
            if len(bhs) > 1:
                assert ishash(bhs[0][0])
                assert isinstance(bhs[0][1], int)
                if bhs[0][1] == bhs[1][1]:
                    assert bhs[0][0] > bhs[1][0]
                else:
                    assert bhs[0][1] > bhs[1][1]
示例#11
0
 def mk_ls(h, r):
     ls = LockSet()
     votes = [Locked(Signature(i, h, r), '0'*32) for i in range(ls.eligible_votes)]
     for i, v in enumerate(votes):
         ls.add(v)
     return ls
示例#12
0
class RoundManager(object):

    timeout = 1  # secs
    timeout_round_factor = 1.2

    def __init__(self, heightmanager, round=0):
        self.hm = heightmanager
        self.cm = heightmanager.cm
        self.log = self.hm.log
        assert isinstance(round, int)
        self.round = round
        self.height = heightmanager.height
        self.lockset = LockSet()
        self.proposal = None
        self.lock = None
        self.timeout_time = None
        print('A:%d Created RoundManager H:%d R:%d' %
              (self.cm.coinbase, self.hm.height, self.round))

    def setup_timeout(self):
        "setup a timeout for waiting for a proposal"
        if self.timeout_time is not None or self.proposal:
            return
        now = self.cm.env.now
        delay = self.timeout * self.timeout_round_factor**self.round
        self.timeout_time = now + delay
        return delay

    def add_vote(self, v, force_replace=False):
        self.log('rm.adding',
                 vote=v,
                 proposal=self.proposal,
                 pid=id(self.proposal))
        self.lockset.add(v, force_replace)

    def add_proposal(self, p):
        self.log('rm.adding', proposal=p, old=self.proposal)
        assert not self.proposal
        self.proposal = p

    def process(self):
        self.log('in rm.process', height=self.hm.height, round=self.round)

        assert self.cm.round == self.round
        assert self.cm.height == self.hm.height == self.height
        if self.cm.stopped:
            self.log('stopped not creating proposal')
            return
        p = self.propose()
        if isinstance(p, BlockProposal):
            self.cm.add_block(p.block)
        if p:
            self.cm.broadcast(p)
        v = self.vote()
        if v:
            self.cm.broadcast(v)
        assert not self.proposal or self.lock

    def propose(self):
        proposer = self.cm.proposer(self.height, self.round)
        self.log('in propose',
                 proposer=proposer,
                 proposal=self.proposal,
                 lock=self.lock)
        if proposer != self.cm.coinbase:
            return
        if self.proposal:
            assert self.proposal.signature.address == self.cm.coinbase
            assert self.lock
            return

        lockset = self.cm.last_valid_lockset
        self.log('in creating proposal', lockset=lockset)

        if self.round == 0 or lockset.has_noquorum:
            cl = self.cm.last_committing_lockset  # quorum which signs prev block
            assert cl.has_quorum
            block = Block(self.cm.coinbase, self.hm.height, self.round,
                          self.cm.head.hash, cl)
            proposal = BlockProposal(self.signature(), lockset, block)
        elif lockset.has_quorum_possible:
            bh = lockset.has_quorum_possible
            proposal = VotingInstruction(self.signature(), lockset, bh)
        else:
            raise Exception('invalid lockset')
        self.log('created proposal', p=proposal)
        self.proposal = proposal

        return proposal

    def vote(self):
        if self.lock:
            return  # voted in this round
        self.log('in vote', proposal=self.proposal, pid=id(self.proposal))

        # get last lock on height
        last_lock = self.hm.last_lock

        if self.proposal:
            if isinstance(self.proposal, VotingInstruction):
                assert self.proposal.lockset.has_quorum_possible
                self.log('voting on instruction')
                v = Locked(self.signature(), self.proposal.blockhash)
            elif not isinstance(last_lock, Locked):
                assert isinstance(self.proposal, BlockProposal)
                assert self.proposal.lockset.has_noquorum or self.round == 0
                assert self.proposal.block.prevhash == self.cm.head.hash
                assert self.cm.chainmanager.validate_block(
                    self.proposal.block)  # fixme
                self.log('voting proposed block')
                v = Locked(self.signature(), self.proposal.block.hash)
            else:  # repeat vote
                self.log('voting on last vote')
                v = Locked(self.signature(), last_lock.blockhash)
        elif self.timeout_time is not None and self.cm.env.now >= self.timeout_time:
            if isinstance(last_lock, Locked):  # repeat vote
                self.log('timeout voting on last vote')
                v = Locked(self.signature(), last_lock.blockhash)
            else:
                self.log('timeout voting not locked')
                v = NotLocked(self.signature())
        else:
            return
        self.log('voted', vote=v)
        self.lock = v
        assert self.hm.last_lock == self.lock
        self.lockset.add(v)
        return v

    def signature(self):
        return Signature(self.cm.coinbase, self.cm.height, self.cm.round)