Ejemplo n.º 1
0
    def validate_node_staking_score(self, node_staking_score: NodeStakingScore,
                                    since_block_number: BlockNumber) -> None:
        node_staking_score.validate()

        # make sure all proof's have valid signatures
        node_staking_score.check_signature_validity()

        # need to make sure we have the up-to-date peer chain so that our stake calculation is correct.
        # RewardProofSenderBlockMissing
        if not self.chaindb.is_in_canonical_chain(
                node_staking_score.head_hash_of_sender_chain):
            raise RewardProofSenderBlockMissing(
                "Our chain for chain_address {} appears to be out of date. We need the block with hash {}"
                .format(
                    encode_hex(node_staking_score.sender),
                    encode_hex(node_staking_score.head_hash_of_sender_chain)))

        # The node staking score proof cannot know about a block in the future.
        claimed_header = self.chaindb.get_block_header_by_hash(
            node_staking_score.head_hash_of_sender_chain)
        if claimed_header.timestamp > node_staking_score.timestamp:
            raise ValidationError(
                "Reward proof has a timestamp that is less than the claimed head hash of sender chain. This is impossible because it cannot know about the future, and not allowed."
            )

        # we have to make sure the head_hash_of_sender_chain is the newest block before the given timestamp
        next_block_number = claimed_header.block_number + 1
        try:
            next_header = self.chaindb.get_canonical_block_header_by_number(
                next_block_number, node_staking_score.sender)
            if next_header.timestamp < node_staking_score.timestamp:
                # it found a block that is earlier than the proof timestamp, but is newer than the claimed header. This means they claimed the wrong header
                raise ValidationError(
                    "Reward proof has incorrect header hash for the sender chain, at the timestamp the proof was made. "
                    "The timestamp of the node staking score is {}. The timestamp of the next block is {}. "
                    "The block number of the next block is {}. The hash of the next block is {}"
                    .format(node_staking_score.timestamp,
                            next_header.timestamp, next_header.block_number,
                            encode_hex(next_header.hash)))
        except HeaderNotFound:
            pass

        # We need to validate that the previous reward block in proof equals the latest reward block
        if node_staking_score.since_block_number != since_block_number:
            raise ValidationError(
                "Reward proof has incorrect since_block_number. Got {}, but should be {}"
                .format(node_staking_score.since_block_number,
                        since_block_number))

        if node_staking_score.score < 0 or node_staking_score.score > 1000000:
            raise ValidationError(
                'Node staking score is out of allowed range of 0 to 1,000,000. Got {}'
                .format(node_staking_score.score))
def _test_block_rewards_system():
    #The genesis chain will be adding a reward block. We need to generate fake NodeStakingScores from a bunch of other
    #nodes

    # testdb = LevelDB('/home/tommy/.local/share/helios/instance_test/mainnet/chain/full/')
    # testdb = JournalDB(testdb)
    testdb = create_reward_test_blockchain_database()

    chain = MainnetChain(testdb, GENESIS_PRIVATE_KEY.public_key.to_canonical_address(), GENESIS_PRIVATE_KEY)
    coin_mature_time = chain.get_vm(timestamp=Timestamp(int(time.time()))).consensus_db.coin_mature_time_for_staking
    min_time_between_blocks = chain.get_vm(timestamp=Timestamp(int(time.time()))).min_time_between_blocks
    # now = int(time.time())
    # start = now - max((coin_mature_time * 2), (min_time_between_blocks*20))
    # key_balance_dict = {
    #     private_keys[0]: (to_wei(10, 'ether'), start),
    #     private_keys[1]: (to_wei(200, 'ether'), start + min_time_between_blocks * 1),
    #     private_keys[2]: (to_wei(340, 'ether'), start + min_time_between_blocks * 2),
    #     private_keys[3]: (to_wei(1000, 'ether'), start + min_time_between_blocks * 3),
    #     private_keys[4]: (to_wei(1400, 'ether'), start + min_time_between_blocks * 4),
    #     private_keys[5]: (to_wei(2400, 'ether'), start + min_time_between_blocks * 5),
    #     private_keys[6]: (to_wei(3000, 'ether'), start + min_time_between_blocks * 6),
    #     private_keys[7]: (to_wei(4000, 'ether'), start + min_time_between_blocks * 7),
    #     private_keys[8]: (to_wei(1000, 'ether'), start + min_time_between_blocks * 8),
    #     private_keys[9]: (to_wei(10000, 'ether'), now-coin_mature_time+1),# immature
    # }
    # create_dev_fixed_blockchain_database(testdb, key_balance_dict)

    chain = MainnetChain(testdb, GENESIS_PRIVATE_KEY.public_key.to_canonical_address(), GENESIS_PRIVATE_KEY)

    # class NodeStakingScore(rlp.Serializable, metaclass=ABCMeta):
    #     fields = [
    #         ('recipient_node_wallet_address', address),
    #         ('score', f_big_endian_int),
    #         ('since_block_number', f_big_endian_int),
    #         ('timestamp', f_big_endian_int),
    #         ('v', big_endian_int),
    #         ('r', big_endian_int),
    #         ('s', big_endian_int),
    #     ]

    node_staking_scores = []

    score = 1000000
    for private_key in private_keys:
        node_staking_score = NodeStakingScore(recipient_node_wallet_address = GENESIS_PRIVATE_KEY.public_key.to_canonical_address(),
                                              score = int(score),
                                              since_block_number = 0,
                                              timestamp = int(time.time()),
                                              head_hash_of_sender_chain = chain.chaindb.get_canonical_head_hash(private_key.public_key.to_canonical_address()),
                                              v = 0,
                                              r = 0,
                                              s = 0,
                                              )
        signed_node_staking_score = node_staking_score.get_signed(private_key,MAINNET_NETWORK_ID)
        node_staking_scores.append(signed_node_staking_score)
        score = score/5

    chain = MainnetChain(testdb, GENESIS_PRIVATE_KEY.public_key.to_canonical_address(), GENESIS_PRIVATE_KEY)

    node_staking_scores.sort(key=lambda x: -1* x.score)
    for node_staking_score in node_staking_scores:
        node_staking_score.validate()
        print(node_staking_score.is_signature_valid)
        print(node_staking_score.sender)
        print(node_staking_score.score, chain.get_mature_stake(node_staking_score.sender, node_staking_score.timestamp))


    reward_bundle = chain.get_consensus_db().create_reward_bundle_for_block(GENESIS_PRIVATE_KEY.public_key.to_canonical_address(), node_staking_scores, at_timestamp = int(time.time()))


    chain.get_consensus_db().validate_reward_bundle(reward_bundle, GENESIS_PRIVATE_KEY.public_key.to_canonical_address(), int(time.time()))

    print('AAAAAAAAAAA')
    print(reward_bundle.reward_type_1.amount)
    print(reward_bundle.reward_type_2.amount)
    print(reward_bundle.reward_type_2.proof[0].score)


    initial_balance = chain.get_vm().state.account_db.get_balance(GENESIS_PRIVATE_KEY.public_key.to_canonical_address())
    print("balance before reward = ", initial_balance)

    chain.import_current_queue_block_with_reward(reward_bundle.reward_type_2.proof)

    final_balance = chain.get_vm().state.account_db.get_balance(GENESIS_PRIVATE_KEY.public_key.to_canonical_address())
    print("balance after reward = ",final_balance)
    assert((reward_bundle.reward_type_1.amount + reward_bundle.reward_type_2.amount) == (final_balance- initial_balance))

    print("waiting {} seconds before importing the next block".format(min_time_between_blocks))
    time.sleep(min_time_between_blocks)

    proof_chain = MainnetChain(testdb, private_keys[1].public_key.to_canonical_address(), private_keys[1])
    mature_stake = proof_chain.get_mature_stake()
    print("proof chain mature stake")
    print(mature_stake)

    staking_score = proof_chain.get_signed_peer_score_string_private_key(private_keys[1].to_bytes(), private_keys[0].public_key.to_canonical_address())
    staking_score = staking_score.copy(score=1532)
    staking_score = staking_score.get_signed(private_keys[1], proof_chain.network_id)
    print('staking score')
    print(staking_score.score)

    # fields = [
    #     ('recipient_node_wallet_address', address),
    #     ('score', f_big_endian_int),  # a score out of 1,000,000
    #     ('since_block_number', f_big_endian_int),
    #     ('timestamp', f_big_endian_int),
    #     ('head_hash_of_sender_chain', hash32),
    #     ('v', big_endian_int),
    #     ('r', big_endian_int),
    #     ('s', big_endian_int),
    # ]
    #
    reward_chain = MainnetChain(testdb, private_keys[0].public_key.to_canonical_address(), private_keys[0])
    reward_bundle = reward_chain.get_consensus_db().create_reward_bundle_for_block(private_keys[0].public_key.to_canonical_address(), [staking_score],at_timestamp=Timestamp(int(time.time())))
    print("reward type 2 amount")
    print(reward_bundle.reward_type_2.amount)
    print("reward type 2 proof")
    print(reward_bundle.reward_type_2.proof)
    reward_chain.import_current_queue_block_with_reward([staking_score])

    # todo: this will fail if the reward block time is too long. Need to manually set it to a small number for the test... or manually make the blocks older?
    print("waiting {} seconds before importing the next block".format(min_time_between_blocks))
    time.sleep(min_time_between_blocks)

    proof_chain = MainnetChain(testdb, private_keys[1].public_key.to_canonical_address(), private_keys[1])
    mature_stake = proof_chain.get_mature_stake()
    print("proof chain mature stake")
    print(mature_stake)

    staking_score = proof_chain.get_signed_peer_score_string_private_key(private_keys[1].to_bytes(), private_keys[
        0].public_key.to_canonical_address())
    staking_score = staking_score.copy(score=1000000)
    staking_score = staking_score.get_signed(private_keys[1], proof_chain.network_id)
    print('staking score')
    print(staking_score.score)

    # fields = [
    #     ('recipient_node_wallet_address', address),
    #     ('score', f_big_endian_int),  # a score out of 1,000,000
    #     ('since_block_number', f_big_endian_int),
    #     ('timestamp', f_big_endian_int),
    #     ('head_hash_of_sender_chain', hash32),
    #     ('v', big_endian_int),
    #     ('r', big_endian_int),
    #     ('s', big_endian_int),
    # ]
    #
    reward_chain = MainnetChain(testdb, private_keys[0].public_key.to_canonical_address(), private_keys[0])
    reward_bundle = reward_chain.get_consensus_db().create_reward_bundle_for_block(
        private_keys[0].public_key.to_canonical_address(), [staking_score], at_timestamp=Timestamp(int(time.time())))
    print("reward type 2 amount")
    print(reward_bundle.reward_type_2.amount)
    print("reward type 2 proof")
    print(reward_bundle.reward_type_2.proof)
    reward_chain.import_current_queue_block_with_reward([staking_score])