예제 #1
0
    def pos_block_pool(self, n=1.5):
        """
        create a snapshot of the transaction pool to account for network traversal time (probably less than 300ms, but let's give a window of 1.5 seconds).
        :param n:
        :return: list of merkle root hashes of the tx pool over last 1.5 seconds
        """
        timestamp = time()
        start_time = timestamp - n

        x = self.sorted_tx_pool(start_time)
        y = self.sorted_tx_pool(timestamp)
        if not y:  # if pool is empty -> return sha256 null
            return [sha256('')], [[]]
        elif x == y:  # if the pool isnt empty but there is no difference then return the only merkle hash possible..
            return [merkle_tx_hash(y)], [y]
        else:  # there is a difference in contents of pool over last 1.5 seconds..
            merkle_hashes = []
            txhashes = []
            if not x:
                merkle_hashes.append(sha256(''))
                x = []
                txhashes.append(x)
            else:
                merkle_hashes.append(merkle_tx_hash(x))
                txhashes.append(x)
            tmp_txhashes = x

            for tx in reversed(self.transaction_pool):
                if tx.txhash in y and tx.txhash not in x:
                    tmp_txhashes.append(tx.txhash)
                    tmp_txhashes.sort()
                    merkle_hashes.append(merkle_tx_hash(tmp_txhashes))
                    txhashes.append(tmp_txhashes)

            return merkle_hashes, txhashes
예제 #2
0
파일: chain.py 프로젝트: thejewce/QRL
    def closest_hash(list_hash):
        """
        returns the closest hash in numerical terms to merkle root hash of all the supplied hashes..
        :param list_hash:
        :return:
        """

        if isinstance(list_hash, list):
            if len(list_hash) == 1:
                return False, False
        if isinstance(list_hash, str):
            if len(list_hash) == 64:
                return False, False

        list_hash.sort()

        root = merkle_tx_hash(list_hash)

        p = []
        for l in list_hash:
            p.append(int(l, 16))

        closest = closest_number(int(root, 16), p)

        return ''.join(list_hash[p.index(closest)]), root
예제 #3
0
파일: test_block.py 프로젝트: zeta1999/QRL
 def test_update_mining_address(self):
     self.block.update_mining_address(dev_config=config.dev, mining_address=bob.address)
     coinbase_tx = Transaction.from_pbdata(self.block.transactions[0])
     self.assertTrue(isinstance(coinbase_tx, CoinBase))
     self.assertEqual(coinbase_tx.addr_to, bob.address)
     hashedtransactions = []
     for tx in self.block.transactions:
         hashedtransactions.append(tx.transaction_hash)
     self.assertEqual(self.block.blockheader.tx_merkle_root, merkle_tx_hash(hashedtransactions))
예제 #4
0
    def create(self, chain, reveal_hash, vote_hash, last_block_number=-1):
        # FIXME: probably this should turn into a constructor
        reveal_hash = reveal_hash
        vote_hash = vote_hash

        data = None
        if last_block_number == -1:
            data = chain.block_chain_buffer.get_last_block(
            )  # m_get_last_block()
        else:
            data = chain.block_chain_buffer.get_block_n(last_block_number)

        last_block_number = data.blockheader.blocknumber
        prev_blockheaderhash = data.blockheader.headerhash

        hashedtransactions = []
        self.transactions = [None]
        fee_reward = 0

        for tx in chain.transaction_pool:
            if tx.subtype == TX_SUBTYPE_TX:
                fee_reward += tx.fee
            hashedtransactions.append(tx.txhash)
            self.transactions.append(tx)  # copy memory rather than sym link

        self.duplicate_transactions = []

        for tx in chain.duplicate_tx_pool:
            self.duplicate_transactions.append(chain.duplicate_tx_pool[tx])

        if not hashedtransactions:
            hashedtransactions = [sha256('')]

        hashedtransactions = merkle_tx_hash(hashedtransactions)

        self.blockheader = BlockHeader()
        self.blockheader.create(chain=chain,
                                blocknumber=last_block_number + 1,
                                reveal_hash=reveal_hash,
                                vote_hash=vote_hash,
                                prev_blockheaderhash=prev_blockheaderhash,
                                hashedtransactions=hashedtransactions,
                                fee_reward=fee_reward)

        coinbase_tx = CoinBase().create(
            self.blockheader,
            chain.block_chain_buffer.get_slave_xmss(last_block_number + 1))
        # coinbase_tx = CoinBase().create(self.blockheader.block_reward + self.blockheader.fee_reward,
        #                                            self.blockheader.headerhash,
        #                                            chain.wallet.address_bundle[0].xmss.get_address(),
        #                                            chain.block_chain_buffer.get_slave_xmss(last_block_number + 1))

        self.transactions[0] = coinbase_tx
        sv_list = chain.block_chain_buffer.get_stake_validators_list(
            last_block_number + 1).sv_list
        coinbase_tx.nonce = sv_list[chain.mining_address].nonce + 1
예제 #5
0
    def validate(self, chain_manager, future_blocks: OrderedDict) -> bool:
        if chain_manager.get_block_is_duplicate(self):
            logger.warning('Duplicate Block #%s %s', self.block_number,
                           bin2hstr(self.headerhash))
            return False

        parent_block = chain_manager.get_block(self.prev_headerhash)

        # If parent block not found in state, then check if its in the future block list
        if not parent_block:
            try:
                parent_block = future_blocks[self.prev_headerhash]
            except KeyError:
                logger.warning('Parent block not found')
                logger.warning('Parent block headerhash %s',
                               bin2hstr(self.prev_headerhash))
                return False

        if not self._validate_parent_child_relation(parent_block):
            logger.warning('Failed to validate blocks parent child relation')
            return False

        if not chain_manager.validate_mining_nonce(self.blockheader):
            logger.warning('Failed PoW Validation')
            return False

        fee_reward = 0
        for index in range(1, len(self.transactions)):
            fee_reward += self.transactions[index].fee

        if len(self.transactions) == 0:
            return False

        try:
            coinbase_txn = Transaction.from_pbdata(self.transactions[0])
            coinbase_amount = coinbase_txn.amount

            if not coinbase_txn.validate_extended(self.block_number):
                return False

        except Exception as e:
            logger.warning('Exception %s', e)
            return False

        hashedtransactions = []

        for tx in self.transactions:
            tx = Transaction.from_pbdata(tx)
            hashedtransactions.append(tx.txhash)

        if not self.blockheader.validate(fee_reward, coinbase_amount,
                                         merkle_tx_hash(hashedtransactions)):
            return False

        return True
예제 #6
0
    def update_mining_address(self, mining_address: bytes):
        coinbase_tx = Transaction.from_pbdata(self.transactions[0])
        coinbase_tx.update_mining_address(mining_address)
        hashedtransactions = [coinbase_tx.txhash]

        for tx in self.transactions:
            hashedtransactions.append(tx.transaction_hash)

        self.blockheader.update_merkle_root(merkle_tx_hash(hashedtransactions))

        self._data.header.MergeFrom(self.blockheader.pbdata)
예제 #7
0
파일: Block.py 프로젝트: younesmovic/QRL
    def create(staking_address: bytes, block_number: int, reveal_hash: bytes,
               prevblock_headerhash: bytes, transactions: list,
               duplicate_transactions: OrderedDict, vote: VoteMetadata,
               signing_xmss: XMSS, nonce: int):

        block = Block()
        block._data.transactions.extend([qrl_pb2.Transaction()
                                         ])  # FIXME: Empty for coinbase?

        # Process transactions
        hashedtransactions = []
        fee_reward = 0

        for tx in transactions:
            if tx.subtype == qrl_pb2.Transaction.TRANSFER:
                fee_reward += tx.fee
            hashedtransactions.append(tx.txhash)
            block._data.transactions.extend(
                [tx.pbdata])  # copy memory rather than sym link

        if not hashedtransactions:
            hashedtransactions = [sha256(b'')]

        txs_hash = merkle_tx_hash(
            hashedtransactions)  # FIXME: Find a better name, type changes

        for tx in duplicate_transactions.values(
        ):  # TODO: Add merkle hash for dup txn
            block._data.duplicate_transactions.extend([tx.pbdata])

        for staker in vote.stake_validator_vote:  # TODO: Add merkle hash for vote
            block._data.vote.extend([vote.stake_validator_vote[staker].pbdata])

        tmp_blockheader = BlockHeader.create(
            staking_address=staking_address,
            blocknumber=block_number,
            reveal_hash=reveal_hash,
            prev_blockheaderhash=prevblock_headerhash,
            hashedtransactions=txs_hash,
            fee_reward=fee_reward)

        block._data.header.MergeFrom(tmp_blockheader.pbdata)

        # Prepare coinbase tx
        coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss)
        coinbase_tx.pbdata.nonce = nonce
        coinbase_tx.sign(signing_xmss)  # Sign after nonce has been set

        # Replace first tx
        block._data.transactions[0].CopyFrom(coinbase_tx.pbdata)

        return block
예제 #8
0
파일: Block.py 프로젝트: kprimice/QRL
    def update_mining_address(self, mining_address: bytes):
        self.transactions[0].update_mining_address(mining_address)
        hashedtransactions = []

        for tx in self.transactions:
            hashedtransactions.append(tx.transaction_hash)

        tmp_blockheader = BlockHeader.create(
            blocknumber=self.block_number,
            prev_blockheaderhash=self.prev_headerhash,
            hashedtransactions=merkle_tx_hash(hashedtransactions),
            fee_reward=self.fee_reward)

        self._data.header.MergeFrom(tmp_blockheader.pbdata)
예제 #9
0
    def create(dev_config: DevConfig, block_number: int,
               prev_headerhash: bytes, prev_timestamp: int, transactions: list,
               miner_address: bytes, seed_height: Optional[int],
               seed_hash: Optional[bytes]):

        block = Block()

        # Process transactions
        hashedtransactions = []
        fee_reward = 0

        for tx in transactions:
            fee_reward += tx.fee

        # Prepare coinbase tx
        total_reward_amount = BlockHeader.block_reward_calc(
            block_number, dev_config) + fee_reward
        coinbase_tx = CoinBase.create(dev_config, total_reward_amount,
                                      miner_address, block_number)
        hashedtransactions.append(coinbase_tx.txhash)
        Block._copy_tx_pbdata_into_block(
            block, coinbase_tx)  # copy memory rather than sym link

        for tx in transactions:
            hashedtransactions.append(tx.txhash)
            Block._copy_tx_pbdata_into_block(
                block, tx)  # copy memory rather than sym link

        txs_hash = merkle_tx_hash(
            hashedtransactions)  # FIXME: Find a better name, type changes

        tmp_blockheader = BlockHeader.create(dev_config=dev_config,
                                             blocknumber=block_number,
                                             prev_headerhash=prev_headerhash,
                                             prev_timestamp=prev_timestamp,
                                             hashedtransactions=txs_hash,
                                             fee_reward=fee_reward,
                                             seed_height=seed_height,
                                             seed_hash=seed_hash)

        block.blockheader = tmp_blockheader

        block._data.header.MergeFrom(tmp_blockheader.pbdata)

        block.set_nonces(dev_config, 0, 0)

        return block
예제 #10
0
 def test_update_mining_address(self):
     alice_xmss = get_alice_xmss()
     bob_xmss = get_bob_xmss()
     block = Block.create(block_number=5,
                          prev_headerhash=bytes(sha2_256(b'test')),
                          prev_timestamp=10,
                          transactions=[],
                          miner_address=alice_xmss.address)
     block.update_mining_address(mining_address=bob_xmss.address)
     coinbase_tx = Transaction.from_pbdata(block.transactions[0])
     self.assertTrue(isinstance(coinbase_tx, CoinBase))
     self.assertEqual(coinbase_tx.addr_to, bob_xmss.address)
     hashedtransactions = []
     for tx in block.transactions:
         hashedtransactions.append(tx.transaction_hash)
     self.assertEqual(block.blockheader.tx_merkle_root,
                      merkle_tx_hash(hashedtransactions))
예제 #11
0
    def create(block_number: int, prev_block_headerhash: bytes,
               prev_block_timestamp: int, transactions: list,
               miner_address: bytes):

        block = Block()

        # Process transactions
        hashedtransactions = []
        fee_reward = 0

        for tx in transactions:
            fee_reward += tx.fee

        # Prepare coinbase tx
        total_reward_amount = BlockHeader.block_reward_calc(
            block_number) + fee_reward
        coinbase_tx = CoinBase.create(total_reward_amount, miner_address,
                                      block_number)
        hashedtransactions.append(coinbase_tx.txhash)
        block._data.transactions.extend([coinbase_tx.pbdata
                                         ])  # copy memory rather than sym link

        for tx in transactions:
            hashedtransactions.append(tx.txhash)
            block._data.transactions.extend(
                [tx.pbdata])  # copy memory rather than sym link

        txs_hash = merkle_tx_hash(
            hashedtransactions)  # FIXME: Find a better name, type changes

        tmp_blockheader = BlockHeader.create(
            blocknumber=block_number,
            prev_block_headerhash=prev_block_headerhash,
            prev_block_timestamp=prev_block_timestamp,
            hashedtransactions=txs_hash,
            fee_reward=fee_reward)

        block.blockheader = tmp_blockheader

        block._data.header.MergeFrom(tmp_blockheader.pbdata)

        block.set_nonces(0, 0)

        return block
예제 #12
0
파일: Block.py 프로젝트: fanff/QRL
    def create(mining_nonce: int,
               block_number: int,
               prevblock_headerhash: bytes,
               transactions: list,
               signing_xmss: XMSS,
               master_address: bytes,
               nonce: int):

        block = Block()
        block._data.transactions.extend([qrl_pb2.Transaction()])  # FIXME: Empty for coinbase?

        # Process transactions
        hashedtransactions = []
        fee_reward = 0

        for tx in transactions:
            fee_reward += tx.fee
            hashedtransactions.append(tx.txhash)
            block._data.transactions.extend([tx.pbdata])  # copy memory rather than sym link

        if not hashedtransactions:
            hashedtransactions = [sha256(b'')]

        txs_hash = merkle_tx_hash(hashedtransactions)           # FIXME: Find a better name, type changes

        tmp_blockheader = BlockHeader.create(blocknumber=block_number,
                                             mining_nonce=mining_nonce,
                                             PK=signing_xmss.pk(),
                                             prev_blockheaderhash=prevblock_headerhash,
                                             hashedtransactions=txs_hash,
                                             fee_reward=fee_reward)

        block._data.header.MergeFrom(tmp_blockheader.pbdata)

        # Prepare coinbase tx
        coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss, master_address)
        coinbase_tx.pbdata.nonce = nonce
        coinbase_tx.sign(signing_xmss)  # Sign after nonce has been set

        # Replace first tx
        block._data.transactions[0].CopyFrom(coinbase_tx.pbdata)

        return block
예제 #13
0
    def create(block_number: int, prevblock_headerhash: bytes,
               transactions: list, signing_xmss: XMSS, master_address: bytes,
               nonce: int):

        block = Block()
        block._data.transactions.extend([qrl_pb2.Transaction()
                                         ])  # FIXME: Empty for coinbase?

        # Process transactions
        hashedtransactions = []
        fee_reward = 0

        for tx in transactions:
            fee_reward += tx.fee
            hashedtransactions.append(tx.txhash)
            block._data.transactions.extend(
                [tx.pbdata])  # copy memory rather than sym link

        if not hashedtransactions:
            hashedtransactions = [sha256(b'')]

        txs_hash = merkle_tx_hash(
            hashedtransactions)  # FIXME: Find a better name, type changes

        tmp_blockheader = BlockHeader.create(
            blocknumber=block_number,
            PK=signing_xmss.pk,
            prev_blockheaderhash=prevblock_headerhash,
            hashedtransactions=txs_hash,
            fee_reward=fee_reward)

        block._data.header.MergeFrom(tmp_blockheader.pbdata)

        # Prepare coinbase tx
        coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss,
                                      master_address)
        coinbase_tx.pbdata.nonce = nonce
        coinbase_tx.sign(signing_xmss)  # Sign after nonce has been set

        # Replace first tx
        block._data.transactions[0].CopyFrom(coinbase_tx.pbdata)

        return block
예제 #14
0
파일: block.py 프로젝트: thejewce/QRL
    def create(self, chain, hashchain_link, reveal_list=None, vote_hashes=None, last_block_number=-1):
        # FIXME: probably this should turn into a constructor
        if not reveal_list:
            reveal_list = []
        if not vote_hashes:
            vote_hashes = []

        data = None
        if last_block_number == -1:
            data = chain.block_chain_buffer.get_last_block()  # m_get_last_block()
        else:
            data = chain.block_chain_buffer.get_block_n(last_block_number)

        last_block_number = data.blockheader.blocknumber
        prev_blockheaderhash = data.blockheader.headerhash

        hashedtransactions = []
        self.transactions = [None]

        for tx in chain.transaction_pool:
            hashedtransactions.append(tx.txhash)
            self.transactions.append(tx)  # copy memory rather than sym link

        if not hashedtransactions:
            hashedtransactions = sha256('')

        hashedtransactions = merkle_tx_hash(hashedtransactions)

        self.blockheader = BlockHeader()
        self.blockheader.create(chain=chain,
                                blocknumber=last_block_number + 1,
                                reveal_list=reveal_list,
                                vote_hashes=vote_hashes,
                                hashchain_link=hashchain_link,
                                prev_blockheaderhash=prev_blockheaderhash,
                                hashedtransactions=hashedtransactions)

        coinbase_tx = transaction.CoinBase().create(self.blockheader.block_reward, self.blockheader.headerhash,
                                                    chain.my[0][1])
        self.transactions[0] = coinbase_tx
        coinbase_tx.nonce = chain.block_chain_buffer.get_stxn_state(last_block_number + 1, chain.mining_address)[0] + 1
예제 #15
0
파일: block.py 프로젝트: thejewce/QRL
    def validate_block(self, chain, verify_block_reveal_list=True):  # check validity of new block..
        """
        block validation
        :param chain:
        :param verify_block_reveal_list:
        :return:
        """
        b = self.blockheader
        last_blocknum = b.blocknumber - 1

        if len(self.transactions) == 0:
            logger.warning('BLOCK : There must be atleast 1 txn')
            return False

        coinbase_tx = self.transactions[0]

        try:
            if coinbase_tx.subtype != transaction.TX_SUBTYPE_COINBASE:
                logger.warning('BLOCK : First txn must be a COINBASE txn')
                return False
        except Exception as e:
            logger.exception(e)
            return False

        if coinbase_tx.txfrom != self.blockheader.stake_selector:
            logger.info('Non matching txto and stake_selector')
            logger.info('txto: %s stake_selector %s', coinbase_tx.txfrom, self.blockheader.stake_selector)
            return False

        if coinbase_tx.amount != self.blockheader.block_reward:
            logger.info('Block_reward doesnt match')
            logger.info('Found: %d Expected: %d', coinbase_tx.amount, self.blockheader.block_reward)
            return False

        if b.timestamp == 0 and b.blocknumber > 0:
            logger.warning('Invalid block timestamp ')
            return False

        if b.block_reward != b.block_reward_calc():
            logger.warning('Block reward incorrect for block: failed validation')
            return False

        if b.epoch != b.blocknumber / config.dev.blocks_per_epoch:
            logger.warning('Epoch incorrect for block: failed validation')
            return False

        if b.blocknumber == 1:
            x = 0
            for tx in self.transactions:
                if tx.subtype == transaction.TX_SUBTYPE_STAKE:
                    if tx.txfrom == b.stake_selector:
                        x = 1
                        hash, _ = chain.select_hashchain(chain.m_blockchain[-1].blockheader.headerhash,
                                                         b.stake_selector,
                                                         tx.hash, blocknumber=1)

                        if sha256(b.hash) != hash or hash not in tx.hash:
                            logger.warning('Hashchain_link does not hash correctly to terminator: failed validation')
                            return False
            if x != 1:
                logger.warning('Stake selector not in block.stake: failed validation')
                return False
        else:  # we look in stake_list for the hash terminator and hash to it..
            found = False
            terminator = sha256(b.hash)
            for _ in range(b.blocknumber - (b.epoch * config.dev.blocks_per_epoch) + 1):
                terminator = sha256(terminator)
            tmp_stake_list = chain.state.stake_list_get()
            for st in tmp_stake_list:
                if st[0] == b.stake_selector:
                    found = True

                    if terminator != st[1][-1]:
                        logger.warning('Supplied hash does not iterate to terminator: failed validation')
                        return False

            if not found:
                logger.warning('Stake selector not in stake_list for this epoch..')
                return False

            if len(b.reveal_list) != len(set(b.reveal_list)):
                logger.warning('Repetition in reveal_list')
                return False

            if verify_block_reveal_list:
                i = 0
                for r in b.reveal_list:
                    t = sha256(r)
                    for _ in range(b.blocknumber - (
                                b.epoch * config.dev.blocks_per_epoch) + 1):  # +1 as reveal has 1 extra hash
                        t = sha256(t)
                    for s in tmp_stake_list:
                        if t == s[1][-1]:
                            i += 1

                if i != len(b.reveal_list):
                    logger.warning('Not all the reveal_hashes are valid..')
                    return False

                i = 0
                target_chain = select_target_hashchain(b.prev_blockheaderhash)
                for r in b.vote_hashes:
                    t = sha256(r)
                    for x in range(b.blocknumber - (b.epoch * config.dev.blocks_per_epoch)):
                        t = sha256(t)
                    for s in tmp_stake_list:
                        if t == s[1][target_chain]:
                            i += 1

                if i != len(b.vote_hashes):
                    logger.warning('Not all the reveal_hashes are valid..')
                    return False

        if b.generate_headerhash() != b.headerhash:
            logger.warning('Headerhash false for block: failed validation')
            return False

        tmp_last_block = chain.block_chain_buffer.get_block_n(last_blocknum)

        if tmp_last_block.blockheader.headerhash != b.prev_blockheaderhash:
            logger.warning('Headerhash not in sequence: failed validation')
            return False

        if tmp_last_block.blockheader.blocknumber != b.blocknumber - 1:
            logger.warning('Block numbers out of sequence: failed validation')
            return False

        if not self.validate_tx_in_block():
            logger.warning('Block validate_tx_in_block error: failed validation')
            return False

        if len(self.transactions) == 1:
            txhashes = sha256('')
        else:
            txhashes = []
            for tx_num in range(1, len(self.transactions)):
                tx = self.transactions[tx_num]
                txhashes.append(tx.txhash)

        if merkle_tx_hash(txhashes) != b.tx_merkle_root:
            logger.warning('Block hashedtransactions error: failed validation')
            return False

        return True
예제 #16
0
def audit_chain(qrl_client, dbg_addr):
    """
    Request and store each blockself.
    Iterate thru each block, replaying each transaction to recreate address balances.
    Query each address comparing the reported vs calculated balances.
    """
    total_blocks = 0
    block_store = dict()
    balances_store = dict()
    transaction_store = dict()
    if dbg_addr is not None:
        dbg_addr = bytes.fromhex(dbg_addr[1:]).hex()
    # load the blocks
    while True:
        request = qrl_pb2.GetObjectReq(query=str(total_blocks).encode(
            encoding='ascii'))
        response = qrl_client.GetObject(request)
        if not response.HasField('block_extended'):
            # we reached the end of the chain
            break
        # get and store block
        block = response.block_extended
        block_store[total_blocks] = block
        total_blocks += 1

    logging.info('loaded up to block number {}'.format(total_blocks))

    # re-create balances by replaying each block
    for block_num in range(0, total_blocks):
        block = block_store[block_num]

        # store transactions in each block
        for txn in range(0, len(block.extended_transactions)):
            txhash = block.extended_transactions[txn].tx.transaction_hash.hex()
            transaction_store[txhash] = block.extended_transactions[txn]

        # handle coinbase
        address = block.extended_transactions[0].tx.coinbase.addr_to.hex()
        amount = block.extended_transactions[0].tx.coinbase.amount
        if not address in balances_store:
            balances_store[address] = 0
        balances_store[address] += amount
        if dbg_addr in [address]:
            print('coinbase amnt {} -> Q{} via blk {}'.format(
                amount, address, block_num))

        # handle all other transactions outside of coinbase
        for txn in range(1, len(block.extended_transactions)):
            tx = block.extended_transactions[txn].tx
            addr_from = block.extended_transactions[txn].addr_from.hex()
            tx_hash = tx.transaction_hash.hex()
            if tx.fee > 0:
                balances_store[addr_from] -= tx.fee
                if dbg_addr in [addr_from]:
                    print('fee amnt {} Q{} -> Q{} via tx {}'.format(
                        tx.fee, addr_from, address, tx_hash))
            if tx.HasField('transfer'):
                update_balances(balances_store, addr_from, tx.transfer,
                                dbg_addr, tx_hash)
            if tx.HasField('multi_sig_spend'):
                if has_multi_sig_spend_executed(qrl_client,
                                                tx.transaction_hash):
                    addr_from = tx.multi_sig_spend.multi_sig_address.hex()
                    update_balances(balances_store, addr_from,
                                    tx.multi_sig_spend, dbg_addr, tx_hash)

    logging.info('loaded {} addresses and {} transactions'.format(
        len(balances_store), len(transaction_store)))

    # audit each block, checking the block header and building a list
    for block_num in range(0, total_blocks):
        block = block_store[block_num]
        if block_num > 0:
            blockPrev = block_store[block_num - 1]
            if block.header.hash_header_prev != blockPrev.header.hash_header:
                logging.error('prev block error at {}'.format(block_num))
            if block.header.timestamp_seconds < blockPrev.header.timestamp_seconds:
                logging.error('timestamp error at {}'.format(block_num))
        if block.header.block_number != block_num:
            logging.error('block num error at {}'.format(block_num))
        hashedtransactions = [
            block.extended_transactions[0].tx.transaction_hash
        ]
        reward = block.header.reward_block
        for txn in range(1, len(block.extended_transactions)):
            reward += block.extended_transactions[txn].tx.fee
            hashedtransactions.append(
                block.extended_transactions[txn].tx.transaction_hash)
        if block.extended_transactions[0].tx.coinbase.amount != reward:
            logging.error('coinbase error at {}'.format(block_num))
        if block.header.reward_fee + block.header.reward_block != reward:
            logging.error('reward error at {}'.format(block_num))
        merkle_root = merkle_tx_hash(hashedtransactions)
        if block.header.merkle_root != merkle_root:
            logging.error('merkle_root error at {}'.format(block_num))

    for addr in balances_store:
        try:
            balance = audit_address(qrl_client, 'Q' + addr, False)
            if balance != balances_store[addr]:
                logging.error('balance for {} does not match'.format('Q' +
                                                                     addr))
                logging.error('node-reported balance: {}'.format(balance))
                logging.error('calculated balance:    {}'.format(
                    balances_store[addr]))
        except:
            logging.error('could not query addr {}'.format('Q' + addr))
            raise
예제 #17
0
    def validate(self, chain_manager, future_blocks: OrderedDict) -> bool:
        if chain_manager.get_block_is_duplicate(self):
            logger.warning('Duplicate Block #%s %s', self.block_number, bin2hstr(self.headerhash))
            return False

        parent_block = chain_manager.get_block(self.prev_headerhash)
        dev_config = chain_manager.get_config_by_block_number(self.block_number)

        # If parent block not found in state, then check if its in the future block list
        if not parent_block:
            try:
                parent_block = future_blocks[self.prev_headerhash]
            except KeyError:
                logger.warning('Parent block not found')
                logger.warning('Parent block headerhash %s', bin2hstr(self.prev_headerhash))
                return False

        if not self._validate_parent_child_relation(parent_block):
            logger.warning('Failed to validate blocks parent child relation')
            return False

        if not chain_manager.validate_mining_nonce(self.blockheader, dev_config):
            logger.warning('Failed PoW Validation')
            return False

        if len(self.transactions) == 0:
            return False

        try:
            state_container = chain_manager.new_state_container(set(),
                                                                self.block_number,
                                                                False,
                                                                None)

            coinbase_txn = Transaction.from_pbdata(self.transactions[0])
            coinbase_amount = coinbase_txn.amount

            if not coinbase_txn.validate_all(state_container):
                return False

            if self.block_number != 2078158:
                for proto_tx in self.transactions[1:]:
                    if proto_tx.WhichOneof('transactionType') == 'coinbase':
                        logger.warning("Multiple coinbase transaction found")
                        return False

        except Exception as e:
            logger.warning('Exception %s', e)
            return False

        # Build transaction merkle tree, calculate fee reward, and then see if BlockHeader also agrees.
        hashedtransactions = []

        for tx in self.transactions:
            tx = Transaction.from_pbdata(tx)
            hashedtransactions.append(tx.txhash)

        fee_reward = 0
        for index in range(1, len(self.transactions)):
            fee_reward += self.transactions[index].fee

        qn = Qryptonight()
        seed_block = chain_manager.get_block_by_number(qn.get_seed_height(self.block_number))

        self.blockheader._seed_height = seed_block.block_number
        self.blockheader._seed_hash = seed_block.headerhash

        if not self.blockheader.validate(fee_reward,
                                         coinbase_amount,
                                         merkle_tx_hash(hashedtransactions),
                                         dev_config):
            return False

        return True