예제 #1
0
    def load_state(self) -> bool:
        try:
            self.pstate.prev_stake_validators_tracker = StakeValidatorsTracker.from_json(
                self.pstate.get_prev_stake_validators_tracker())
            self.pstate.stake_validators_tracker = StakeValidatorsTracker.from_json(
                self.pstate.get_stake_validators_tracker())

            block_number = self.pstate.get_state_version()
            block = Block.from_json(self.pstate.get_block(block_number))
            self.blockchain.append(block)

            return True
        except Exception:
            return False
예제 #2
0
    def test_add_future_sv(self):
        alice_xmss = get_alice_xmss()
        slave_xmss = XMSS(alice_xmss.height, alice_xmss.get_seed())

        stake_validators_tracker = StakeValidatorsTracker.create()

        stake_transaction = StakeTransaction.create(10, alice_xmss, slave_xmss.pk(), b'1111')
        stake_validators_tracker.add_sv(100, stake_transaction, 1)

        total_stake_amount = stake_validators_tracker.get_total_stake_amount()
        self.assertNotEqual(100, total_stake_amount)
예제 #3
0
    def test_add_sv(self):
        alice_xmss = get_alice_xmss()
        slave_xmss = XMSS(alice_xmss.height, alice_xmss.get_seed())

        stake_validators_tracker = StakeValidatorsTracker.create()

        stake_transaction = StakeTransaction.create(0, alice_xmss, slave_xmss.pk(), b'1111')
        stake_validators_tracker.add_sv(100, stake_transaction, 1)

        balance = stake_validators_tracker.get_stake_balance(alice_xmss.get_address().encode())
        self.assertEqual(100, balance)

        total_stake_amount = stake_validators_tracker.get_total_stake_amount()
        self.assertEqual(100, total_stake_amount)
        stake_validators_tracker.to_json()
예제 #4
0
    def test_add_many_and_save(self):
        with set_wallet_dir("test_wallet"):
            with State() as state:
                self.assertIsNotNone(state)

                chain = Chain(state)
                alice_xmss = get_alice_xmss()
                staking_address = bytes(alice_xmss.get_address().encode())

                with patch('qrl.core.config.dev.disk_writes_after_x_blocks'):
                    qrl.core.config.dev.disk_writes_after_x_blocks = 4

                    prev = bytes()
                    address_state_dict = dict()
                    address_state_dict[staking_address] = AddressState.create(
                        address=staking_address,
                        nonce=0,
                        balance=100,
                        pubhashes=[])
                    for i in range(10):
                        tmp_block1 = Block.create(
                            staking_address=staking_address,
                            block_number=i,
                            reveal_hash=bytes(),
                            prevblock_headerhash=prev,
                            transactions=[],
                            duplicate_transactions=OrderedDict(),
                            vote=VoteMetadata(),
                            signing_xmss=alice_xmss,
                            nonce=address_state_dict[staking_address].nonce +
                            1)
                        prev = tmp_block1.headerhash

                        res = chain.add_block(tmp_block1, address_state_dict,
                                              StakeValidatorsTracker(),
                                              b'1001', alice_xmss)

                        address_state_dict[staking_address].increase_nonce()
                        address_state_dict[
                            staking_address].balance += tmp_block1.block_reward

                        self.assertEqual(
                            i, chain.height
                        )  # FIXME: wrong name, it is not height but max_index

                        self.assertTrue(res)

                print(qrl.core.config.dev.disk_writes_after_x_blocks)
예제 #5
0
    def test_getStats(self):
        db_state = Mock(spec=State)
        db_state.stake_validators_tracker = StakeValidatorsTracker()
        db_state.total_coin_supply = MagicMock(return_value=1000)

        p2p_factory = Mock(spec=P2PFactory)
        p2p_factory.sync_state = SyncState()
        p2p_factory.connections = 23
        p2p_factory.pos = Mock()
        p2p_factory.pos.stake = False

        buffered_chain = Mock(spec=BufferedChain)
        buffered_chain.height = 0
        buffered_chain._chain = Mock()
        buffered_chain._chain.blockchain = []

        buffered_chain.get_block = MagicMock(return_value=None)
        buffered_chain.state = db_state

        qrlnode = QRLNode(db_state)
        qrlnode.set_p2pfactory(p2p_factory)
        qrlnode.set_chain(buffered_chain)

        service = PublicAPIService(qrlnode)
        stats = service.GetStats(request=qrl_pb2.GetStatsReq, context=None)

        # self.assertEqual(__version__, stats.node_info.version)  # FIXME
        self.assertEqual(qrl_pb2.NodeInfo.UNSYNCED, stats.node_info.state)
        self.assertEqual(23, stats.node_info.num_connections)
        # self.assertEqual("testnet", stats.node_info.network_id)  # FIXME

        self.assertEqual(0, stats.epoch)
        self.assertEqual(0, stats.uptime_network)

        self.assertEqual(0, stats.stakers_count)

        self.assertEqual(0, stats.block_last_reward)
        self.assertEqual(0, stats.block_time_mean)
        self.assertEqual(0, stats.block_time_sd)

        self.assertEqual(105000000, stats.coins_total_supply)
        self.assertEqual(1000, stats.coins_emitted)
        self.assertEqual(0, stats.coins_atstake)

        logger.info(stats)
예제 #6
0
    def test_last_block(self):
        with set_wallet_dir("test_wallet"):
            with State() as state:
                self.assertIsNotNone(state)

                chain = Chain(state)
                alice_xmss = get_alice_xmss()
                staking_address = bytes(alice_xmss.get_address().encode())

                address_state_dict = dict()
                address_state_dict[staking_address] = AddressState.create(
                    address=staking_address,
                    nonce=0,
                    balance=100,
                    pubhashes=[],
                    tokens=dict())

                tmp_block1 = Block.create(
                    staking_address=staking_address,
                    block_number=0,
                    reveal_hash=bytes(),
                    prevblock_headerhash=bytes(),
                    transactions=[],
                    duplicate_transactions=OrderedDict(),
                    vote=VoteMetadata(),
                    signing_xmss=alice_xmss,
                    nonce=address_state_dict[staking_address].nonce + 1)

                res = chain.add_block(tmp_block1, address_state_dict,
                                      StakeValidatorsTracker(), b'101',
                                      alice_xmss)
                address_state_dict[staking_address].increase_nonce()
                address_state_dict[
                    staking_address].balance += tmp_block1.block_reward
                self.assertTrue(res)
                self.assertEqual(
                    0, chain.height
                )  # FIXME: wrong name, it is not height but max_index

                last_block = chain.get_last_block()
                self.assertEqual(tmp_block1, last_block)
예제 #7
0
 def test_create1(self):
     stake_validators_tracker = StakeValidatorsTracker.create()
     self.assertIsInstance(stake_validators_tracker, StakeValidatorsTracker)
예제 #8
0
파일: State.py 프로젝트: younesmovic/QRL
    def __init__(self):
        self._db = db.DB()  # generate db object here

        # FIXME: Move to BufferedChain
        self.stake_validators_tracker = StakeValidatorsTracker()
예제 #9
0
파일: State.py 프로젝트: younesmovic/QRL
class State:
    # FIXME: Rename to PersistentState
    # FIXME: Move blockchain caching/storage over here
    # FIXME: Improve key generation

    def __init__(self):
        self._db = db.DB()  # generate db object here

        # FIXME: Move to BufferedChain
        self.stake_validators_tracker = StakeValidatorsTracker()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self._db is not None:
            del self._db
            self._db = None

    def put_epoch_seed(self, epoch_seed):
        try:
            self._db.put('epoch_seed', epoch_seed)
        except Exception as e:
            # FIXME: Review
            logger.exception(e)
            return False

    def get_epoch_seed(self):
        try:
            return self._db.get('epoch_seed')
        except Exception as e:
            # FIXME: Review
            logger.warning("get_epoch_seed: %s %s", type(e), e)
            return False

    def get_lattice_public_key(self, address):
        try:
            return set(self._db.get(b'lattice_' + address))
        except KeyError:
            return set()
        except Exception as e:
            logger.exception(e)
            return False

    def put_lattice_public_key(self, lattice_public_key_txn):
        address = lattice_public_key_txn.txfrom
        lattice_public_keys = self.get_lattice_public_key(address)
        lattice_public_keys.add(lattice_public_key_txn.kyber_pk)
        self._db.put(b'lattice_' + address, list(lattice_public_keys))

    #########################################
    #########################################
    #########################################
    #########################################
    #########################################

    def uptodate(self,
                 height):  # check state db marker to current blockheight.
        # FIXME: Remove
        return height == self._blockheight()

    def _blockheight(self):
        # FIXME: Remove
        return self._db.get('blockheight')

    def _set_blockheight(self, height):
        # FIXME: Remove
        return self._db.put('blockheight', height)

    #########################################
    #########################################
    #########################################
    #########################################
    #########################################

    def update_last_tx(self, block):
        if len(block.transactions) == 0:
            return
        last_txn = []

        try:
            last_txn = self._db.get('last_txn')
        except:  # noqa
            pass

        for protobuf_txn in block.transactions[-20:]:
            txn = Transaction.from_pbdata(protobuf_txn)
            if txn.subtype == qrl_pb2.Transaction.TRANSFER:
                last_txn.insert(
                    0, [txn.to_json(), block.block_number, block.timestamp])

        del last_txn[20:]
        self._db.put('last_txn', last_txn)

    def get_last_txs(self):
        try:
            last_txn = self._db.get('last_txn')
        except:  # noqa
            return []

        txs = []
        for tx_metadata in last_txn:
            tx_json, block_num, block_ts = tx_metadata
            tx = Transaction.from_json(tx_json)
            txs.append(tx)

        return txs

    #########################################
    #########################################
    #########################################
    #########################################
    #########################################

    def update_address_tx_hashes(self, addr: bytes, new_txhash: bytes):
        txhash = self.get_address_tx_hashes(addr)
        txhash.append(new_txhash)

        # FIXME:  Json does not support bytes directly | Temporary workaround
        tmp_hashes = [bin2hstr(item) for item in txhash]

        self._db.put(b'txn_' + addr, tmp_hashes)

    def update_stake_validators(
            self, stake_validators_tracker: StakeValidatorsTracker):
        self.stake_validators_tracker = stake_validators_tracker

    def get_address_tx_hashes(self, addr: bytes) -> List[bytes]:
        try:
            tx_hashes = self._db.get(b'txn_' + addr)
        except KeyError:
            tx_hashes = []
        except Exception as e:
            logger.exception(e)
            tx_hashes = []

        tx_hashes = [bytes(hstr2bin(item)) for item in tx_hashes]

        return tx_hashes

    #########################################
    #########################################
    #########################################
    #########################################
    #########################################

    def get_txn_count(self, addr):
        try:
            return self._db.get((b'txn_count_' + addr))
        except KeyError:
            pass
        except Exception as e:
            # FIXME: Review
            logger.error('Exception in get_txn_count')
            logger.exception(e)

        return 0

    def increase_txn_count(self, addr: bytes):
        # FIXME: This should be transactional
        last_count = self.get_txn_count(addr)
        self._db.put(b'txn_count_' + addr, last_count + 1)

    #########################################
    #########################################
    #########################################
    #########################################
    #########################################

    def update_tx_metadata(self, block):
        if len(block.transactions) == 0:
            return

        # FIXME: Inconsistency in the keys/types
        for protobuf_txn in block.transactions:
            txn = Transaction.from_pbdata(protobuf_txn)
            if txn.subtype in (qrl_pb2.Transaction.TRANSFER,
                               qrl_pb2.Transaction.COINBASE):
                self._db.put(
                    bin2hstr(txn.txhash),
                    [txn.to_json(), block.block_number, block.timestamp])

                if txn.subtype == qrl_pb2.Transaction.TRANSFER:
                    self.update_address_tx_hashes(txn.txfrom, txn.txhash)

                self.update_address_tx_hashes(txn.txto, txn.txhash)
                self.increase_txn_count(txn.txto)
                self.increase_txn_count(txn.txfrom)

    def get_tx_metadata(self, txhash: bytes):
        try:
            tx_metadata = self._db.get(bin2hstr(txhash))
        except Exception:
            return None
        if tx_metadata is None:
            return None
        txn_json, block_number, _ = tx_metadata
        return Transaction.from_json(txn_json), block_number

    def update_vote_metadata(self, block):
        if len(block.transactions) == 0:
            return

        total_stake_amount = self.stake_validators_tracker.get_total_stake_amount(
        )
        voted_weight = 0
        # FIXME: Inconsistency in the keys/types
        for protobuf_txn in block.vote:
            vote = Transaction.from_pbdata(protobuf_txn)
            voted_weight += self.stake_validators_tracker.get_stake_balance(
                vote.txfrom)

        self._db.put(b'vote_' + str(block.block_number).encode(),
                     [voted_weight, total_stake_amount])

    def get_vote_metadata(self, blocknumber: int):
        try:
            return self._db.get(b'vote_' + str(blocknumber).encode())
        except Exception:
            return None

    #########################################
    #########################################
    #########################################
    #########################################
    #########################################

    def _get_address_state(self, address: bytes) -> AddressState:
        data = self._db.get_raw(address)
        if data is None:
            raise KeyError("{} not found".format(address))
        pbdata = qrl_pb2.AddressState()
        pbdata.ParseFromString(bytes(data))
        address_state = AddressState(pbdata)
        return address_state

    def _save_address_state(self, address_state: AddressState):
        data = address_state.pbdata.SerializeToString()
        self._db.put_raw(address_state.address, data)

    def get_address(self, address: bytes) -> AddressState:
        # FIXME: Avoid two calls to know if address is not recognized (merged with is used)
        try:
            return self._get_address_state(address)
        except KeyError:
            # FIXME: Check all cases where address is not found
            return AddressState.create(
                address=address,
                nonce=config.dev.default_nonce,
                balance=config.dev.default_account_balance,
                pubhashes=[])

    def nonce(self, addr: bytes) -> int:
        return self.get_address(addr).nonce

    def balance(self, addr: bytes) -> int:
        return self.get_address(addr).balance

    def pubhash(self, addr: bytes):
        return self.get_address(addr).pubhashes

    def address_used(self, address: bytes):
        # FIXME: Probably obsolete
        try:
            return self._get_address_state(address)
        except KeyError:
            return False
        except Exception as e:
            # FIXME: Review
            logger.error('Exception in address_used')
            logger.exception(e)
            raise

    def return_all_addresses(self):
        addresses = []
        for key, data in self._db.RangeIter(b'Q', b'Qz'):
            pbdata = qrl_pb2.AddressState()
            pbdata.ParseFromString(bytes(data))
            address_state = AddressState(pbdata)
            addresses.append(address_state)
        return addresses

    def zero_all_addresses(self):
        for k, v in self._db.RangeIter(b'Q', b'Qz'):
            self._db.delete(k)
        logger.info('Reset Finished')
        self._set_blockheight(0)

    #########################################
    #########################################
    #########################################
    #########################################
    #########################################

    def total_coin_supply(self):
        # FIXME: This is temporary code. NOT SCALABLE. It is easy to keep a global count
        all_addresses = self.return_all_addresses()
        coins = 0
        for a in all_addresses:
            coins = coins + a.balance
        return coins