Ejemplo n.º 1
0
    def apply_witness_tx(
        self, block: BamiBlock, witness_tx: Tuple[int, ChainState]
    ) -> None:
        state = witness_tx[1]
        state_hash = take_hash(state)
        seq_num = witness_tx[0]

        if not self.should_witness_chain_point(block.com_id, block.public_key, seq_num):
            # This is invalid witnessing - react
            raise InvalidWitnessTransactionException(
                "Received invalid witness transaction",
                block.com_id,
                block.public_key,
                seq_num,
            )
        self.state_db.add_witness_vote(
            block.com_id, seq_num, state_hash, block.public_key
        )
        self.state_db.add_chain_state(block.com_id, seq_num, state_hash, state)

        chain_id = block.com_id
        if self.tracked_blocks.get(chain_id):
            for block_dot, tracked_block in self.tracked_blocks[chain_id].items():
                if (
                    block_dot[0] <= seq_num
                    and state.get(shorten(tracked_block.public_key))
                    and state.get(shorten(tracked_block.public_key)) == (True, True)
                ):
                    self.update_risk(chain_id, block.public_key, block_dot[0])
Ejemplo n.º 2
0
 def witness(self, chain_id: bytes, seq_num: int) -> None:
     """
     Witness the chain up to a sequence number.
     If chain is known and data exists:
      - Will create a witness block, link to latest known blocks and share in the community.
     Otherwise:
      - Do nothing
     Args:
         chain_id: id of the chain
         seq_num: sequence number of the block:
     """
     chain = self.persistence.get_chain(chain_id)
     if chain:
         witness_blob = self.build_witness_blob(chain_id, seq_num)
         if witness_blob:
             blk = self.create_signed_block(
                 block_type=WITNESS_TYPE,
                 transaction=witness_blob,
                 prefix=b"w",
                 com_id=chain_id,
                 use_consistent_links=False,
             )
             self.logger.debug(
                 "Creating witness block on chain %s: %s, com_dot %s, pers_dot %s",
                 shorten(blk.com_id),
                 seq_num,
                 blk.com_dot,
                 blk.pers_dot,
             )
             self.share_in_community(blk, chain_id)
Ejemplo n.º 3
0
    def block_response(
        self, block: BamiBlock, wait_time: float = None, wait_blocks: int = None
    ) -> BlockResponse:
        # Analyze the risk of accepting this block
        stat = self.state_db.get_closest_peers_status(block.com_id, block.com_seq_num)
        # If there is no information or chain is forked or
        peer_id = shorten(block.public_key)

        if not stat or not stat[1].get(peer_id):
            # Check that it is not infinite
            if (wait_time and wait_time > self.settings.max_wait_time) or (
                wait_blocks and wait_blocks > self.settings.max_wait_block
            ):
                return BlockResponse.REJECT
            return BlockResponse.DELAY
        if not stat[1][peer_id][1] or not stat[1][peer_id][0]:
            # If chain is forked or negative balance => reject
            return BlockResponse.REJECT

        # Verify the risk of missing some information:
        #  - There is diverse peers building upon the block

        # TODO: revisit that - number should depend on total number of peers in community.
        # 1. Diversity on the block building
        f = self.settings.diversity_confirm

        if len(self.peer_conf[(block.com_id, block.com_seq_num)]) >= f:
            return BlockResponse.CONFIRM
        else:
            return BlockResponse.DELAY
Ejemplo n.º 4
0
 def get_last_peer_status(self, chain_id: bytes) -> ChainState:
     """Get last balance of peers in the community"""
     v = dict()
     for p in self.chain_peers[chain_id]:
         v[shorten(p)] = (
             self.get_balance(p) >= 0,
             not self.is_chain_forked(chain_id, p),
         )
     return ChainState(v)
Ejemplo n.º 5
0
 def __str__(self):
     # This makes debugging and logging easier
     return "Block {0} from ...{1}:{2} links {3} for {4} type {5} cseq {6} cid {7}.{8}".format(
         self.short_hash,
         shorten(self.public_key),
         self.sequence_number,
         self.links,
         self.transaction,
         self.type,
         self.com_seq_num,
         self.com_prefix,
         self.com_id,
     )
Ejemplo n.º 6
0
 def short_hash(self):
     return shorten(self.hash)
Ejemplo n.º 7
0
 def update_risk(self, chain_id: bytes, conf_peer_id: bytes, target_seq_num: int):
     print("Risk update: ", shorten(conf_peer_id), target_seq_num)
     self.peer_conf[(chain_id, target_seq_num)][conf_peer_id] += 1
Ejemplo n.º 8
0
def test_encode_decode_links(keys_fixture):
    links = Links(((1, shorten(keys_fixture)), ))
    raw_bytes = encode_links(links)
    assert decode_links(raw_bytes) == links
Ejemplo n.º 9
0
def test_shorten_size(keys_fixture):
    s_k = shorten(keys_fixture)
    assert len(s_k) == KEY_LEN
Ejemplo n.º 10
0
 def test_short_hash(self):
     block = FakeBlock()
     assert shorten(block.hash) == block.short_hash
Ejemplo n.º 11
0
    def test_state_updates(self):
        chain_id = self.minter
        value = Decimal(12.00, self.con)
        dot = Dot((1, b"123123"))

        self.state.apply_mint(
            chain_id, dot, GENESIS_LINK, self.minter, value, store_update=True
        )
        assert self.state.get_balance(self.minter) == value
        assert not self.state.is_chain_forked(chain_id, self.minter)
        spend_value = Decimal(12.00, self.con)
        spend_dot = Dot((2, b"23123"))
        self.state.apply_spend(
            chain_id,
            GENESIS_LINK,
            Links((dot,)),
            spend_dot,
            self.spender,
            self.receiver,
            spend_value,
            store_status_update=True,
        )
        assert float(self.state.get_balance(self.spender)) == 0
        assert not self.state.is_chain_forked(chain_id, self.spender)

        claim_dot = Dot((3, b"23323"))

        self.state.apply_confirm(
            chain_id,
            self.receiver,
            Links((spend_dot,)),
            claim_dot,
            self.spender,
            spend_dot,
            spend_value,
            store_update=True,
        )

        v = self.state.get_closest_peers_status(chain_id, 1)
        assert v is not None
        assert v[0] == 1
        assert len(v[1]) == 1
        assert v[1].get(shorten(self.spender)) == (True, True)

        v = self.state.get_closest_peers_status(chain_id, 2)
        assert v is not None
        assert (
            (v[0] == 2)
            and (len(v[1]) == 1)
            and (v[1].get(shorten(self.spender)) == (True, True))
        )

        v = self.state.get_closest_peers_status(chain_id, 3)
        assert v is not None
        assert (
            v[0] == 3
            and len(v[1]) == 2
            and (v[1].get(shorten(self.spender)) == (True, True))
            and (v[1].get(shorten(self.receiver)) == (True, True))
        )

        assert v[1] == self.state.get_last_peer_status(chain_id)