Пример #1
0
    async def test_timestamp(self, initial_blockchain):
        blocks, b = initial_blockchain
        # Time too far in the past
        block_bad = FullBlock(
            HeaderBlock(
                blocks[9].header_block.proof_of_space,
                blocks[9].header_block.proof_of_time,
                blocks[9].header_block.challenge,
                Header(
                    HeaderData(
                        blocks[9].header_block.header.data.prev_header_hash,
                        blocks[9].header_block.header.data.timestamp - 1000,
                        blocks[9].header_block.header.data.filter_hash,
                        blocks[9].header_block.header.data.proof_of_space_hash,
                        blocks[9].header_block.header.data.body_hash,
                        blocks[9].header_block.header.data.extension_data,
                    ),
                    blocks[9].header_block.header.harvester_signature,
                ),
            ),
            blocks[9].body,
        )
        assert (await b.receive_block(
            block_bad,
            blocks[8].header_block)) == ReceiveBlockResult.INVALID_BLOCK

        # Time too far in the future
        block_bad = FullBlock(
            HeaderBlock(
                blocks[9].header_block.proof_of_space,
                blocks[9].header_block.proof_of_time,
                blocks[9].header_block.challenge,
                Header(
                    HeaderData(
                        blocks[9].header_block.header.data.prev_header_hash,
                        uint64(int(time.time() + 3600 * 3)),
                        blocks[9].header_block.header.data.filter_hash,
                        blocks[9].header_block.header.data.proof_of_space_hash,
                        blocks[9].header_block.header.data.body_hash,
                        blocks[9].header_block.header.data.extension_data,
                    ),
                    blocks[9].header_block.header.harvester_signature,
                ),
            ),
            blocks[9].body,
        )

        assert (await b.receive_block(
            block_bad,
            blocks[8].header_block)) == ReceiveBlockResult.INVALID_BLOCK
Пример #2
0
    async def header_signature(
        self, header_signature: farmer_protocol.HeaderSignature
    ) -> OutboundMessageGenerator:
        """
        Signature of header hash, by the harvester. This is enough to create an unfinished
        block, which only needs a Proof of Time to be finished. If the signature is valid,
        we call the unfinished_block routine.
        """
        async with self.store.lock:
            candidate: Optional[
                Tuple[Body, HeaderData,
                      ProofOfSpace]] = await self.store.get_candidate_block(
                          header_signature.pos_hash)
            if candidate is None:
                log.warning(
                    f"PoS hash {header_signature.pos_hash} not found in database"
                )
                return
            # Verifies that we have the correct header and body self.stored
            block_body, block_header_data, pos = candidate

            assert block_header_data.get_hash() == header_signature.header_hash

            block_header: Header = Header(block_header_data,
                                          header_signature.header_signature)
            header: HeaderBlock = HeaderBlock(pos, None, None, block_header)
            unfinished_block_obj: FullBlock = FullBlock(header, block_body)

        # Propagate to ourselves (which validates and does further propagations)
        request = peer_protocol.UnfinishedBlock(unfinished_block_obj)
        async for m in self.unfinished_block(request):
            # Yield all new messages (propagation to peers)
            yield m
Пример #3
0
 def get_header_block(self, block: FullBlock) -> Optional[HeaderBlock]:
     challenge: Optional[Challenge] = self.get_challenge(block)
     if challenge is None or block.proof_of_time is None:
         return None
     return HeaderBlock(
         block.proof_of_space, block.proof_of_time, challenge, block.header
     )
Пример #4
0
    async def test_body_hash(self, initial_blockchain):
        blocks, b = initial_blockchain
        block_bad = FullBlock(
            HeaderBlock(
                blocks[9].header_block.proof_of_space,
                blocks[9].header_block.proof_of_time,
                blocks[9].header_block.challenge,
                Header(
                    HeaderData(
                        blocks[9].header_block.header.data.prev_header_hash,
                        blocks[9].header_block.header.data.timestamp,
                        blocks[9].header_block.header.data.filter_hash,
                        blocks[9].header_block.header.data.proof_of_space_hash,
                        bytes([1] * 32),
                        blocks[9].header_block.header.data.extension_data,
                    ),
                    blocks[9].header_block.header.harvester_signature,
                ),
            ),
            blocks[9].body,
        )

        assert (await b.receive_block(
            block_bad,
            blocks[8].header_block)) == ReceiveBlockResult.INVALID_BLOCK
    def get_block_header(self) -> HeaderBlock:
        # Create filter
        if self.is_block():
            byte_array_tx: List[bytes32] = []
            removals_names, addition_coins = self.tx_removals_and_additions()

            for coin in addition_coins:
                byte_array_tx.append(bytearray(coin.puzzle_hash))
            for name in removals_names:
                byte_array_tx.append(bytearray(name))

            for coin in self.get_included_reward_coins():
                byte_array_tx.append(bytearray(coin.puzzle_hash))

            bip158: PyBIP158 = PyBIP158(byte_array_tx)
            encoded_filter: bytes = bytes(bip158.GetEncoded())
        else:
            encoded_filter = b""

        return HeaderBlock(
            self.finished_sub_slots,
            self.reward_chain_sub_block,
            self.challenge_chain_sp_proof,
            self.challenge_chain_ip_proof,
            self.reward_chain_sp_proof,
            self.reward_chain_ip_proof,
            self.infused_challenge_chain_ip_proof,
            self.foliage_sub_block,
            self.foliage_block,
            encoded_filter,
            self.transactions_info,
        )
Пример #6
0
    def get_block_header(self, addition_coins=None, removals_names=None) -> HeaderBlock:
        # Create filter
        byte_array_tx: List[bytes32] = []
        if self.is_transaction_block():
            if addition_coins is None or removals_names is None:
                removals_names, addition_coins = self.tx_removals_and_additions()

            assert removals_names is not None
            assert addition_coins is not None
            for coin in addition_coins:
                byte_array_tx.append(bytearray(coin.puzzle_hash))
            for name in removals_names:
                byte_array_tx.append(bytearray(name))

            for coin in self.get_included_reward_coins():
                byte_array_tx.append(bytearray(coin.puzzle_hash))

        bip158: PyBIP158 = PyBIP158(byte_array_tx)
        encoded_filter: bytes = bytes(bip158.GetEncoded())

        return HeaderBlock(
            self.finished_sub_slots,
            self.reward_chain_block,
            self.challenge_chain_sp_proof,
            self.challenge_chain_ip_proof,
            self.reward_chain_sp_proof,
            self.reward_chain_ip_proof,
            self.infused_challenge_chain_ip_proof,
            self.foliage,
            self.foliage_transaction_block,
            encoded_filter,
            self.transactions_info,
        )
Пример #7
0
    async def proof_of_time_finished(
        self, request: timelord_protocol.ProofOfTimeFinished
    ) -> OutboundMessageGenerator:
        """
        A proof of time, received by a peer timelord. We can use this to complete a block,
        and call the block routine (which handles propagation and verification of blocks).
        """
        async with self.store.lock:
            dict_key = (
                request.proof.challenge_hash,
                request.proof.number_of_iterations,
            )

            unfinished_block_obj: Optional[
                FullBlock] = await self.store.get_unfinished_block(dict_key)
            if not unfinished_block_obj:
                log.warning(
                    f"Received a proof of time that we cannot use to complete a block {dict_key}"
                )
                return
            prev_full_block = await self.store.get_block(
                unfinished_block_obj.prev_header_hash)
            assert prev_full_block
            prev_block: HeaderBlock = prev_full_block.header_block
            difficulty: uint64 = self.blockchain.get_next_difficulty(
                unfinished_block_obj.prev_header_hash)
            assert prev_block.challenge

        challenge: Challenge = Challenge(
            request.proof.challenge_hash,
            unfinished_block_obj.header_block.proof_of_space.get_hash(),
            request.proof.output.get_hash(),
            uint32(prev_block.challenge.height + 1),
            uint64(prev_block.challenge.total_weight + difficulty),
            uint64(prev_block.challenge.total_iters +
                   request.proof.number_of_iterations),
        )

        new_header_block = HeaderBlock(
            unfinished_block_obj.header_block.proof_of_space,
            request.proof,
            challenge,
            unfinished_block_obj.header_block.header,
        )
        new_full_block: FullBlock = FullBlock(new_header_block,
                                              unfinished_block_obj.body)

        async with self.store.lock:
            sync_mode = await self.store.get_sync_mode()

        if sync_mode:
            async with self.store.lock:
                await self.store.add_potential_future_block(new_full_block)
        else:
            async for msg in self.block(peer_protocol.Block(new_full_block)):
                yield msg
Пример #8
0
    async def get_header_block_at(self,
                                  heights: List[uint32]) -> List[HeaderBlock]:
        if len(heights) == 0:
            return []

        heights_db = tuple(heights)
        formatted_str = f'SELECT block from header_blocks WHERE height in ({"?," * (len(heights_db) - 1)}?)'
        cursor = await self.db.execute(formatted_str, heights_db)
        rows = await cursor.fetchall()
        await cursor.close()
        return [HeaderBlock.from_bytes(row[0]) for row in rows]
def batch_pre_validate_blocks(
    constants_dict: Dict,
    blocks_pickled: Dict[bytes, bytes],
    header_blocks_pickled: List[bytes],
    transaction_generators: List[Optional[bytes]],
    check_filter: bool,
    expected_difficulty: List[uint64],
    expected_sub_slot_iters: List[uint64],
    validate_transactions: bool,
) -> List[bytes]:
    assert len(header_blocks_pickled) == len(transaction_generators)
    blocks = {}
    for k, v in blocks_pickled.items():
        blocks[k] = BlockRecord.from_bytes(v)
    results: List[PreValidationResult] = []
    constants: ConsensusConstants = dataclass_from_dict(
        ConsensusConstants, constants_dict)
    for i in range(len(header_blocks_pickled)):
        try:
            header_block: HeaderBlock = HeaderBlock.from_bytes(
                header_blocks_pickled[i])
            generator: Optional[bytes] = transaction_generators[i]
            required_iters, error = validate_finished_header_block(
                constants,
                BlockCache(blocks),
                header_block,
                check_filter,
                expected_difficulty[i],
                expected_sub_slot_iters[i],
            )
            cost_result: Optional[CostResult] = None
            error_int: Optional[uint16] = None
            if error is not None:
                error_int = uint16(error.code.value)
            if constants_dict["NETWORK_TYPE"] == NetworkType.MAINNET.value:
                cost_result = None
            else:
                if not error and generator is not None and validate_transactions:
                    cost_result = calculate_cost_of_program(
                        SerializedProgram.from_bytes(generator),
                        constants.CLVM_COST_RATIO_CONSTANT)
            results.append(
                PreValidationResult(error_int, required_iters, cost_result))
        except Exception:
            error_stack = traceback.format_exc()
            log.error(f"Exception: {error_stack}")
            results.append(
                PreValidationResult(uint16(Err.UNKNOWN.value), None, None))
    return [bytes(r) for r in results]
Пример #10
0
 async def test_harvester_signature(self, initial_blockchain):
     blocks, b = initial_blockchain
     # Time too far in the past
     block_bad = FullBlock(
         HeaderBlock(
             blocks[9].header_block.proof_of_space,
             blocks[9].header_block.proof_of_time,
             blocks[9].header_block.challenge,
             Header(
                 blocks[9].header_block.header.data,
                 PrivateKey.from_seed(b"0").sign_prepend(b"random junk"),
             ),
         ),
         blocks[9].body,
     )
     assert (await b.receive_block(block_bad)) == ReceiveBlockResult.INVALID_BLOCK
Пример #11
0
    async def get_header_blocks_in_range(
        self,
        start: int,
        stop: int,
    ) -> Dict[bytes32, HeaderBlock]:

        formatted_str = f"SELECT header_hash, block from header_blocks WHERE height >= {start} and height <= {stop}"

        cursor = await self.db.execute(formatted_str)
        rows = await cursor.fetchall()
        await cursor.close()
        ret: Dict[bytes32, HeaderBlock] = {}
        for row in rows:
            header_hash_bytes, sub_block_bytes = row
            header_hash = bytes.fromhex(header_hash_bytes)
            ret[header_hash] = HeaderBlock.from_bytes(sub_block_bytes)

        return ret
Пример #12
0
    async def test_invalid_pos(self, initial_blockchain):
        blocks, b = initial_blockchain

        bad_pos = [i for i in blocks[9].header_block.proof_of_space.proof]
        bad_pos[0] = uint8((bad_pos[0] + 1) % 256)
        # Proof of space invalid
        block_bad = FullBlock(
            HeaderBlock(
                ProofOfSpace(
                    blocks[9].header_block.proof_of_space.challenge_hash,
                    blocks[9].header_block.proof_of_space.pool_pubkey,
                    blocks[9].header_block.proof_of_space.plot_pubkey,
                    blocks[9].header_block.proof_of_space.size,
                    bad_pos,
                ),
                blocks[9].header_block.proof_of_time,
                blocks[9].header_block.challenge,
                blocks[9].header_block.header,
            ),
            blocks[9].body,
        )
        assert (await b.receive_block(block_bad)) == ReceiveBlockResult.INVALID_BLOCK
Пример #13
0
    def _create_block(
        self,
        test_constants: Dict,
        challenge_hash: bytes32,
        height: uint32,
        prev_header_hash: bytes32,
        prev_iters: uint64,
        prev_weight: uint64,
        timestamp: uint64,
        difficulty: uint64,
        ips: uint64,
        seed: bytes,
    ) -> FullBlock:
        """
        Creates a block with the specified details. Uses the stored plots to create a proof of space,
        and also evaluates the VDF for the proof of time.
        """
        prover = None
        plot_pk = None
        plot_sk = None
        qualities: List[bytes] = []
        for pn in range(num_plots):
            # Allow passing in seed, to create reorgs and different chains
            seeded_pn = (pn + 17 * int.from_bytes(seed, "big")) % num_plots
            filename = self.filenames[seeded_pn]
            plot_pk = plot_pks[seeded_pn]
            plot_sk = plot_sks[seeded_pn]
            prover = DiskProver(os.path.join(self.plot_dir, filename))
            qualities = prover.get_qualities_for_challenge(challenge_hash)
            if len(qualities) > 0:
                break

        assert prover
        assert plot_pk
        assert plot_sk
        if len(qualities) == 0:
            raise NoProofsOfSpaceFound("No proofs for this challenge")

        proof_xs: bytes = prover.get_full_proof(challenge_hash, 0)
        proof_of_space: ProofOfSpace = ProofOfSpace(
            challenge_hash, pool_pk, plot_pk, k, [uint8(b) for b in proof_xs])
        number_iters: uint64 = pot_iterations.calculate_iterations(
            proof_of_space, difficulty, ips, test_constants["MIN_BLOCK_TIME"])

        disc: int = create_discriminant(
            challenge_hash, test_constants["DISCRIMINANT_SIZE_BITS"])
        start_x: ClassGroup = ClassGroup.from_ab_discriminant(2, 1, disc)
        y_cl, proof_bytes = create_proof_of_time_nwesolowski(
            disc, start_x, number_iters, disc, n_wesolowski)

        output = ClassgroupElement(y_cl[0], y_cl[1])

        proof_of_time = ProofOfTime(
            challenge_hash,
            number_iters,
            output,
            n_wesolowski,
            [uint8(b) for b in proof_bytes],
        )

        coinbase: CoinbaseInfo = CoinbaseInfo(
            height,
            block_rewards.calculate_block_reward(uint32(height)),
            coinbase_target,
        )
        coinbase_sig: PrependSignature = pool_sk.sign_prepend(bytes(coinbase))
        fees_target: FeesTarget = FeesTarget(fee_target, uint64(0))
        solutions_generator: bytes32 = sha256(seed).digest()
        cost = uint64(0)
        body: Body = Body(coinbase, coinbase_sig, fees_target, None,
                          solutions_generator, cost)

        header_data: HeaderData = HeaderData(
            prev_header_hash,
            timestamp,
            bytes([0] * 32),
            proof_of_space.get_hash(),
            body.get_hash(),
            bytes([0] * 32),
        )

        header_hash_sig: PrependSignature = plot_sk.sign_prepend(
            header_data.get_hash())

        header: Header = Header(header_data, header_hash_sig)

        challenge = Challenge(
            challenge_hash,
            proof_of_space.get_hash(),
            proof_of_time.get_hash(),
            height,
            uint64(prev_weight + difficulty),
            uint64(prev_iters + number_iters),
        )
        header_block = HeaderBlock(proof_of_space, proof_of_time, challenge,
                                   header)

        full_block: FullBlock = FullBlock(header_block, body)

        return full_block
    async def create(
        key_config: Dict,
        config: Dict,
        db_path: Path,
        constants: Dict,
        name: str = None,
    ):
        self = WalletStateManager()
        self.config = config
        self.constants = constants

        if name:
            self.log = logging.getLogger(name)
        else:
            self.log = logging.getLogger(__name__)
        self.lock = asyncio.Lock()

        self.db_connection = await aiosqlite.connect(db_path)
        self.wallet_store = await WalletStore.create(self.db_connection)
        self.tx_store = await WalletTransactionStore.create(self.db_connection)
        self.puzzle_store = await WalletPuzzleStore.create(self.db_connection)
        self.user_store = await WalletUserStore.create(self.db_connection)
        self.lca = None
        self.sync_mode = False
        self.height_to_hash = {}
        self.block_records = await self.wallet_store.get_lca_path()
        genesis = FullBlock.from_bytes(self.constants["GENESIS_BLOCK"])
        self.genesis = genesis
        self.state_changed_callback = None
        self.pending_tx_callback = None
        self.difficulty_resets_prev = {}
        self.db_path = db_path

        main_wallet_info = await self.user_store.get_wallet_by_id(1)
        assert main_wallet_info is not None

        self.main_wallet = await Wallet.create(config, key_config, self,
                                               main_wallet_info)

        self.wallets = {}
        main_wallet = await Wallet.create(config, key_config, self,
                                          main_wallet_info)
        self.wallets[main_wallet_info.id] = main_wallet

        for wallet_info in await self.get_all_wallets():
            self.log.info(f"wallet_info {wallet_info}")
            if wallet_info.type == WalletType.STANDARD_WALLET:
                if wallet_info.id == 1:
                    continue
                wallet = await Wallet.create(config, key_config, self,
                                             main_wallet_info)
                self.wallets[wallet_info.id] = wallet
            elif wallet_info.type == WalletType.RATE_LIMITED:
                wallet = await RLWallet.create(
                    config,
                    key_config,
                    self,
                    wallet_info,
                    self.main_wallet,
                )
                self.wallets[wallet_info.id] = wallet

        async with self.puzzle_store.lock:
            await self.create_more_puzzle_hashes(from_zero=True)

        if len(self.block_records) > 0:
            # Initializes the state based on the DB block records
            # Header hash with the highest weight
            self.lca = max((item[1].weight, item[0])
                           for item in self.block_records.items())[1]
            for key, value in self.block_records.items():
                self.height_to_hash[value.height] = value.header_hash

            # Checks genesis block is the same in config, as in DB
            assert self.block_records[genesis.header_hash].height == 0
            assert self.block_records[
                genesis.header_hash].weight == genesis.weight
        else:
            # Loads the genesis block if there are no blocks
            genesis_challenge = Challenge(
                genesis.proof_of_space.challenge_hash,
                std_hash(genesis.proof_of_space.get_hash() +
                         genesis.proof_of_time.output.get_hash()),
                None,
            )
            genesis_hb = HeaderBlock(
                genesis.proof_of_space,
                genesis.proof_of_time,
                genesis_challenge,
                genesis.header,
            )
            await self.receive_block(
                BlockRecord(
                    genesis.header_hash,
                    genesis.prev_header_hash,
                    uint32(0),
                    genesis.weight,
                    [],
                    [],
                    genesis_hb.header.data.total_iters,
                    genesis_challenge.get_hash(),
                ),
                genesis_hb,
            )

        return self