예제 #1
0
    def test_receive_paxos_message_try(self):
        # try message
        try_msg = PaxosMessage('TRY', 1)
        try_msg.last_committed_block = GENESIS.block_id

        b = Block(1, GENESIS.block_id, ['a'], 1)
        b.depth = 1
        try_msg.new_block = b.block_id

        self.node.respond = MagicMock()
        self.node.blocktree.nodes.update({b.block_id: b})

        self.node.receive_paxos_message(try_msg, 1)
        assert self.node.respond.called
        assert self.node.s_max_block_depth == b.depth
예제 #2
0
    def test_receive_paxos_message_propose(self):
        propose = PaxosMessage('PROPOSE', 1)

        b = Block(1, GENESIS.block_id, ['a'], 1)
        b.depth = 1

        propose.new_block = GENESIS.block_id
        propose.com_block = GENESIS.block_id

        self.node.respond = MagicMock()
        self.node.receive_paxos_message(propose, 1)

        assert self.node.respond.called
        assert self.node.s_prop_block.block_id == propose.com_block
        assert self.node.s_supp_block.block_id == propose.new_block
예제 #3
0
    def test_receive_paxos_message_try_ok_1(self):
        # try_ok message with no prop/supp block stored locally and message does not contain a propose block
        try_ok = PaxosMessage('TRY_OK', 1)

        b = Block(1, GENESIS.block_id, ['a'], 1)
        b.depth = 1

        self.node.c_request_seq = 1
        self.node.c_new_block = b
        self.node.c_votes = 5
        self.node.broadcast = MagicMock()
        self.node.receive_paxos_message(try_ok, None)
        self.node.blocktree.nodes.update({b.block_id: b})

        assert self.node.broadcast.called
        assert self.node.c_com_block == self.node.c_new_block
예제 #4
0
    def create_block(self):
        """Create a block containing `new_txs` and return it.

        Returns:
            Block: The block that was created.

        """
        logger.debug('create a block')
        # store depth of current head_block (will be parent of new block)
        d = self.blocktree.head_block.depth

        # create block
        self.blocktree.counter += 1
        if len(self.new_txs) < MAX_TXN_COUNT:
            b = Block(self.id, self.blocktree.head_block.block_id,
                      self.new_txs, self.blocktree.counter)
            # create a new, empty list (do not use clear!)
            self.new_txs = []
        else:
            logger.debug(
                'Cannot fit all transactions in the block that is beeing created. Remaining transactions '
                'will be included in the next block.')
            txns_include = self.new_txs[:MAX_TXN_COUNT]
            b = Block(self.id, self.blocktree.head_block.block_id,
                      txns_include, self.blocktree.counter)
            self.new_txs = self.new_txs[MAX_TXN_COUNT:]
            self.readjust_timeout()

        # compute its depth (will be fixed -> depth field is only set once)
        b.depth = d + len(b.txs)

        self.blocktree.db.put(b'counter', str(self.blocktree.counter).encode())

        # add block to blocktree
        self.blocktree.add_block(b)

        # promote node
        if self.state != QUICK:
            self.state = max(QUICK, self.state - 1)
            logger.debug('Got promoted. State = %s', str(self.state))

        # add state of creator node to block
        b.creator_state = self.state

        logger.debug('created block with block id = %s', str(b.block_id))

        return b
예제 #5
0
    def test_receive_paxos_message_propose_ack(self):
        propose_ack = PaxosMessage('PROPOSE_ACK', 1)

        b = Block(1, GENESIS.block_id, ['a'], 1)
        b.depth = 1

        propose_ack.com_block = b.block_id

        self.node.c_request_seq = 1
        self.node.c_votes = 5
        self.node.blocktree.nodes.update({b.block_id: b})

        self.node.broadcast = MagicMock()
        self.node.commit = MagicMock()
        self.node.receive_paxos_message(propose_ack, None)

        assert self.node.broadcast.called

        obj = self.node.broadcast.call_args[0][0]
        assert obj.com_block == propose_ack.com_block
예제 #6
0
from piChain.PaxosNetwork import ConnectionManager
from piChain.blocktree import Blocktree
from piChain.messages import PaxosMessage, Block, RequestBlockMessage, RespondBlockMessage, Transaction, \
    AckCommitMessage
from piChain.config import ACCUMULATION_TIME, MAX_COMMIT_TIME, MAX_TXN_COUNT, TESTING, RECOVERY_BLOCKS_COUNT

# variables representing the state of a node
QUICK = 0
MEDIUM = 1
SLOW = 2

EPSILON = 0.001

# genesis block
GENESIS = Block(-1, None, [], 0)
GENESIS.depth = 0

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
if not TESTING:
    logging.disable(logging.DEBUG)


class Node(ConnectionManager):
    """This class represents a piChain node. It is a subclass of the ConnectionManager class defined in the networking
    module. This allows to directly call functions like broadcast and respond from the networking module and to override
    the receive-methods which are called in the networking module based on the type of the message.

    Args:
        node_index (int): the index of this node into the peers dictionary. The entry defines its ip address and port.
        peers_dict (dict): a dict containing the (ip, port) pairs for all nodes (see examples folder for its structure).