Exemplo n.º 1
0
    async def coin_removed(self, coin: Coin, height: uint32, wallet_id: int):
        """
        Called when coin gets spent
        """

        await self.coin_store.set_spent(coin.name(), height)

        unconfirmed_record: List[
            TransactionRecord] = await self.tx_store.unconfirmed_with_removal_coin(
                coin.name())
        for unconfirmed in unconfirmed_record:
            await self.tx_store.set_confirmed(unconfirmed.name, height)

        self.state_changed("coin_removed", wallet_id)
    async def get_unspent_coins_for_wallet(self, wallet_id: int) -> Set[WalletCoinRecord]:
        """ Returns set of CoinRecords that have not been spent yet for a wallet. """
        async with self.wallet_cache_lock:
            if wallet_id in self.coin_wallet_record_cache:
                wallet_coins: Dict[bytes32, WalletCoinRecord] = self.coin_wallet_record_cache[wallet_id]
                return set(wallet_coins.values())

            coin_set = set()

            cursor = await self.db_connection.execute(
                "SELECT * from coin_record WHERE spent=0 and wallet_id=?",
                (wallet_id,),
            )
            rows = await cursor.fetchall()
            await cursor.close()
            cache_dict = {}
            for row in rows:
                coin = Coin(bytes32(bytes.fromhex(row[8])), bytes32(bytes.fromhex(row[7])), row[9])
                coin_record = WalletCoinRecord(
                    coin, row[1], row[2], row[3], row[4], row[5], row[6], WalletType(row[10]), row[11]
                )
                coin_set.add(coin_record)
                cache_dict[coin.name()] = coin_record

            self.coin_wallet_record_cache[wallet_id] = cache_dict
            return coin_set
Exemplo n.º 3
0
def coin_solution_for_lock_coin(
    prev_coin: Coin,
    subtotal: int,
    coin: Coin,
) -> CoinSolution:
    puzzle_reveal = LOCK_INNER_PUZZLE.curry(prev_coin.as_list(), subtotal)
    coin = Coin(coin.name(), puzzle_reveal.get_tree_hash(), uint64(0))
    coin_solution = CoinSolution(coin, Program.to([puzzle_reveal, 0]))
    return coin_solution
    async def coin_added(self, coin: Coin, index: uint32, coinbase: bool):
        """
        Adding coin to the db
        """
        info = await self.puzzle_store.wallet_info_for_puzzle_hash(
            coin.puzzle_hash)
        assert info is not None
        wallet_id, wallet_type = info
        if coinbase:
            now = uint64(int(time.time()))
            tx_record = TransactionRecord(
                confirmed_at_index=uint32(index),
                created_at_time=now,
                to_puzzle_hash=coin.puzzle_hash,
                amount=coin.amount,
                fee_amount=uint64(0),
                incoming=True,
                confirmed=True,
                sent=uint32(0),
                spend_bundle=None,
                additions=[coin],
                removals=[],
                wallet_id=wallet_id,
                sent_to=[],
            )
            await self.tx_store.add_transaction_record(tx_record)
        else:
            unconfirmed_record = await self.tx_store.unconfirmed_with_addition_coin(
                coin.name())

            if unconfirmed_record:
                # This is the change from this transaction
                await self.tx_store.set_confirmed(unconfirmed_record.name(),
                                                  index)
            else:
                now = uint64(int(time.time()))
                tx_record = TransactionRecord(
                    confirmed_at_index=uint32(index),
                    created_at_time=now,
                    to_puzzle_hash=coin.puzzle_hash,
                    amount=coin.amount,
                    fee_amount=uint64(0),
                    incoming=True,
                    confirmed=True,
                    sent=uint32(0),
                    spend_bundle=None,
                    additions=[coin],
                    removals=[],
                    wallet_id=wallet_id,
                    sent_to=[],
                )
                await self.tx_store.add_transaction_record(tx_record)

        coin_record: WalletCoinRecord = WalletCoinRecord(
            coin, index, uint32(0), False, coinbase, wallet_type, wallet_id)
        await self.wallet_store.add_coin_record(coin_record)
        self.state_changed("coin_added")
Exemplo n.º 5
0
    async def coin_added(self, coin: Coin, height: int, header_hash: bytes32,
                         removals: List[Coin], sub_height: uint32):
        """ Notification from wallet state manager that wallet has been received. """
        self.log.info(f"CC wallet has been notified that {coin} was added")

        search_for_parent: bool = True

        inner_puzzle = await self.inner_puzzle_for_cc_puzhash(coin.puzzle_hash)
        lineage_proof = Program.to((1, [
            coin.parent_coin_info,
            inner_puzzle.get_tree_hash(), coin.amount
        ]))
        await self.add_lineage(coin.name(), lineage_proof)

        for name, lineage_proofs in self.cc_info.lineage_proofs:
            if coin.parent_coin_info == name:
                search_for_parent = False
                break

        if search_for_parent:
            data: Dict[str, Any] = {
                "data": {
                    "action_data": {
                        "api_name": "request_puzzle_solution",
                        "sub_height": sub_height,
                        "coin_name": coin.parent_coin_info,
                        "received_coin": coin.name(),
                    }
                }
            }

            data_str = dict_to_json_str(data)
            await self.wallet_state_manager.create_action(
                name="request_puzzle_solution",
                wallet_id=self.id(),
                type=self.type(),
                callback="puzzle_solution_received",
                done=False,
                data=data_str,
            )
Exemplo n.º 6
0
    async def coin_added(
        self, coin: Coin, height: int, header_hash: bytes32, removals: List[Coin]
    ):
        """ Notification from wallet state manager that wallet has been received. """
        self.log.info("CC wallet has been notified that coin was added")

        search_for_parent: bool = True

        inner_puzzle = await self.inner_puzzle_for_cc_puzzle(coin.puzzle_hash)
        future_parent = CCParent(
            coin.parent_coin_info, inner_puzzle.get_tree_hash(), coin.amount
        )

        await self.add_parent(coin.name(), future_parent)

        for name, ccparent in self.cc_info.parent_info:
            if coin.parent_coin_info == name:
                search_for_parent = False
                break
        # breakpoint()

        if search_for_parent:
            data: Dict[str, Any] = {
                "data": {
                    "action_data": {
                        "api_name": "request_generator",
                        "height": height,
                        "header_hash": header_hash,
                    }
                }
            }

            data_str = dict_to_json_str(data)
            await self.wallet_state_manager.create_action(
                name="request_generator",
                wallet_id=self.wallet_info.id,
                type=self.wallet_info.type,
                callback="generator_received",
                done=False,
                data=data_str,
            )
Exemplo n.º 7
0
    async def generate_zero_val_coin(
            self,
            send=True,
            exclude: List[Coin] = None) -> Optional[SpendBundle]:
        if self.cc_info.my_core is None:
            return None
        if exclude is None:
            exclude = []
        coins = await self.standard_wallet.select_coins(0, exclude)
        if coins == set() or coins is None:
            return None

        origin = coins.copy().pop()
        origin_id = origin.name()

        parent_info = {}
        parent_info[origin_id] = (
            origin.parent_coin_info,
            origin.puzzle_hash,
            origin.amount,
        )

        cc_inner = await self.get_new_inner_hash()
        cc_puzzle = cc_wallet_puzzles.cc_make_puzzle(cc_inner,
                                                     self.cc_info.my_core)
        cc_puzzle_hash = cc_puzzle.get_tree_hash()

        tx = await self.standard_wallet.generate_signed_transaction(
            uint64(0), cc_puzzle_hash, uint64(0), origin_id, coins)
        self.log.info(
            f"Generate zero val coin: cc_puzzle_hash is {cc_puzzle_hash}")
        eve_coin = Coin(origin_id, cc_puzzle_hash, uint64(0))
        if tx is None or tx.spend_bundle is None:
            return None

        eve_spend = cc_generate_eve_spend(eve_coin, cc_puzzle)
        full_spend = SpendBundle.aggregate([tx.spend_bundle, eve_spend])

        future_parent = CCParent(eve_coin.parent_coin_info, cc_inner,
                                 eve_coin.amount)
        eve_parent = CCParent(origin.parent_coin_info, origin.puzzle_hash,
                              origin.amount)

        await self.add_parent(eve_coin.name(), future_parent)
        await self.add_parent(eve_coin.parent_coin_info, eve_parent)

        if send:
            regular_record = TransactionRecord(
                confirmed_at_index=uint32(0),
                created_at_time=uint64(int(time.time())),
                to_puzzle_hash=cc_puzzle_hash,
                amount=uint64(0),
                fee_amount=uint64(0),
                incoming=False,
                confirmed=False,
                sent=uint32(10),
                spend_bundle=full_spend,
                additions=full_spend.additions(),
                removals=full_spend.removals(),
                wallet_id=uint32(1),
                sent_to=[],
                trade_id=None,
            )
            cc_record = TransactionRecord(
                confirmed_at_index=uint32(0),
                created_at_time=uint64(int(time.time())),
                to_puzzle_hash=cc_puzzle_hash,
                amount=uint64(0),
                fee_amount=uint64(0),
                incoming=True,
                confirmed=False,
                sent=uint32(0),
                spend_bundle=full_spend,
                additions=full_spend.additions(),
                removals=full_spend.removals(),
                wallet_id=self.wallet_info.id,
                sent_to=[],
                trade_id=None,
            )
            await self.wallet_state_manager.add_transaction(regular_record)
            await self.wallet_state_manager.add_pending_transaction(cc_record)

        return full_spend
Exemplo n.º 8
0
 def coin_checker_for_farmed_coin_by_coin_id(coin: Coin):
     return create_genesis_or_zero_coin_checker(coin.name())
Exemplo n.º 9
0
    async def set_user_info(
        self,
        interval: uint64,
        limit: uint64,
        origin_parent_id: str,
        origin_puzzle_hash: str,
        origin_amount: uint64,
        admin_pubkey: str,
    ) -> None:
        admin_pubkey_bytes = hexstr_to_bytes(admin_pubkey)

        assert self.rl_info.user_pubkey is not None
        origin = Coin(
            hexstr_to_bytes(origin_parent_id),
            hexstr_to_bytes(origin_puzzle_hash),
            origin_amount,
        )
        rl_puzzle = rl_puzzle_for_pk(
            pubkey=self.rl_info.user_pubkey,
            rate_amount=limit,
            interval_time=interval,
            origin_id=origin.name(),
            clawback_pk=admin_pubkey_bytes,
        )

        rl_puzzle_hash = rl_puzzle.get_tree_hash()

        new_rl_info = RLInfo(
            "user",
            admin_pubkey_bytes,
            self.rl_info.user_pubkey,
            limit,
            interval,
            origin,
            origin.name(),
            rl_puzzle_hash,
            True,
        )
        rl_puzzle_hash = rl_puzzle.get_tree_hash()
        if await self.wallet_state_manager.puzzle_store.puzzle_hash_exists(
            rl_puzzle_hash
        ):
            raise ValueError(
                "Cannot create multiple Rate Limited wallets under the same keys. This will change in a future release."
            )
        index = await self.wallet_state_manager.puzzle_store.index_for_pubkey(
            G1Element.from_bytes(self.rl_info.user_pubkey)
        )
        assert index is not None
        record = DerivationRecord(
            index,
            rl_puzzle_hash,
            self.rl_info.user_pubkey,
            WalletType.RATE_LIMITED,
            self.id(),
        )

        aggregation_puzzlehash = self.rl_get_aggregation_puzzlehash(
            new_rl_info.rl_puzzle_hash
        )
        record2 = DerivationRecord(
            index + 1,
            aggregation_puzzlehash,
            self.rl_info.user_pubkey,
            WalletType.RATE_LIMITED,
            self.id(),
        )
        await self.wallet_state_manager.puzzle_store.add_derivation_paths(
            [record, record2]
        )
        self.wallet_state_manager.set_coin_with_puzzlehash_created_callback(
            aggregation_puzzlehash, self.aggregate_this_coin
        )

        data_str = json.dumps(new_rl_info.to_json_dict())
        new_wallet_info = WalletInfo(
            self.id(), self.wallet_info.name, self.type(), data_str
        )
        await self.wallet_state_manager.user_store.update_wallet(new_wallet_info)
        await self.wallet_state_manager.add_new_wallet(self, self.id())
        self.wallet_info = new_wallet_info
        self.rl_info = new_rl_info
Exemplo n.º 10
0
    async def test_store(self):
        db_filename = Path("blockchain_wallet_store_test.db")

        if db_filename.exists():
            db_filename.unlink()

        db_connection = await aiosqlite.connect(db_filename)
        store = await WalletStore.create(db_connection)
        try:
            coin_1 = Coin(token_bytes(32), token_bytes(32), uint64(12312))
            coin_2 = Coin(token_bytes(32), token_bytes(32), uint64(12312))
            coin_3 = Coin(token_bytes(32), token_bytes(32), uint64(12312))
            coin_4 = Coin(token_bytes(32), token_bytes(32), uint64(12312))
            record_replaced = WalletCoinRecord(coin_1, uint32(8), uint32(0),
                                               False, True,
                                               WalletType.STANDARD_WALLET, 0)
            record_1 = WalletCoinRecord(coin_1, uint32(4), uint32(0), False,
                                        True, WalletType.STANDARD_WALLET, 0)
            record_2 = WalletCoinRecord(coin_2, uint32(5), uint32(0), False,
                                        True, WalletType.STANDARD_WALLET, 0)
            record_3 = WalletCoinRecord(
                coin_3,
                uint32(5),
                uint32(10),
                True,
                False,
                WalletType.STANDARD_WALLET,
                0,
            )
            record_4 = WalletCoinRecord(
                coin_4,
                uint32(5),
                uint32(15),
                True,
                False,
                WalletType.STANDARD_WALLET,
                0,
            )

            # Test add (replace) and get
            assert await store.get_coin_record(coin_1.name()) is None
            await store.add_coin_record(record_replaced)
            await store.add_coin_record(record_1)
            await store.add_coin_record(record_2)
            await store.add_coin_record(record_3)
            await store.add_coin_record(record_4)
            assert await store.get_coin_record(coin_1.name()) == record_1

            # Test persistance
            await db_connection.close()
            db_connection = await aiosqlite.connect(db_filename)
            store = await WalletStore.create(db_connection)
            assert await store.get_coin_record(coin_1.name()) == record_1

            # Test set spent
            await store.set_spent(coin_1.name(), uint32(12))
            assert (await store.get_coin_record(coin_1.name())).spent
            assert (await store.get_coin_record(coin_1.name()
                                                )).spent_block_index == 12

            # No coins at height 3
            assert len(await store.get_unspent_coins_at_height(3)) == 0
            assert len(await store.get_unspent_coins_at_height(4)) == 1
            assert len(await store.get_unspent_coins_at_height(5)) == 4
            assert len(await store.get_unspent_coins_at_height(11)) == 3
            assert len(await store.get_unspent_coins_at_height(12)) == 2
            assert len(await store.get_unspent_coins_at_height(15)) == 1
            assert len(await store.get_unspent_coins_at_height(16)) == 1
            assert len(await store.get_unspent_coins_at_height()) == 1

            assert len(await store.get_unspent_coins_for_wallet(0)) == 1
            assert len(await store.get_unspent_coins_for_wallet(1)) == 0

            coin_5 = Coin(token_bytes(32), token_bytes(32), uint64(12312))
            record_5 = WalletCoinRecord(
                coin_5,
                uint32(5),
                uint32(15),
                False,
                False,
                WalletType.STANDARD_WALLET,
                1,
            )
            await store.add_coin_record(record_5)
            assert len(await store.get_unspent_coins_for_wallet(1)) == 1

            assert len(await store.get_spendable_for_index(100, 1)) == 1
            assert len(await store.get_spendable_for_index(100, 0)) == 1
            assert len(await store.get_spendable_for_index(0, 0)) == 0

            coin_6 = Coin(token_bytes(32), coin_4.puzzle_hash, uint64(12312))
            await store.add_coin_record(record_5)
            record_6 = WalletCoinRecord(
                coin_6,
                uint32(5),
                uint32(15),
                True,
                False,
                WalletType.STANDARD_WALLET,
                2,
            )
            await store.add_coin_record(record_6)
            assert (len(await store.get_coin_records_by_puzzle_hash(
                record_6.coin.puzzle_hash)) == 2)  # 4 and 6
            assert (len(await
                        store.get_coin_records_by_puzzle_hash(token_bytes(32)
                                                              )) == 0)

            assert await store.get_coin_record_by_coin_id(coin_6.name()
                                                          ) == record_6
            assert await store.get_coin_record_by_coin_id(token_bytes(32)
                                                          ) is None

            # BLOCKS
            assert len(await store.get_lca_path()) == 0

            # NOT lca block
            br_1 = BlockRecord(
                token_bytes(32),
                token_bytes(32),
                uint32(0),
                uint128(100),
                None,
                None,
                None,
                None,
                uint64(0),
            )
            assert await store.get_block_record(br_1.header_hash) is None
            await store.add_block_record(br_1, False)
            assert len(await store.get_lca_path()) == 0
            assert await store.get_block_record(br_1.header_hash) == br_1

            # LCA genesis
            await store.add_block_record(br_1, True)
            assert await store.get_block_record(br_1.header_hash) == br_1
            assert len(await store.get_lca_path()) == 1
            assert (await store.get_lca_path())[br_1.header_hash] == br_1

            br_2 = BlockRecord(
                token_bytes(32),
                token_bytes(32),
                uint32(1),
                uint128(100),
                None,
                None,
                None,
                None,
                uint64(0),
            )
            await store.add_block_record(br_2, False)
            assert len(await store.get_lca_path()) == 1
            await store.add_block_to_path(br_2.header_hash)
            assert len(await store.get_lca_path()) == 2
            assert (await store.get_lca_path())[br_2.header_hash] == br_2

            br_3 = BlockRecord(
                token_bytes(32),
                token_bytes(32),
                uint32(2),
                uint128(100),
                None,
                None,
                None,
                None,
                uint64(0),
            )
            await store.add_block_record(br_3, True)
            assert len(await store.get_lca_path()) == 3
            await store.remove_blocks_from_path(1)
            assert len(await store.get_lca_path()) == 2

            await store.rollback_lca_to_block(0)
            assert len(await store.get_unspent_coins_at_height()) == 0

            coin_7 = Coin(token_bytes(32), token_bytes(32), uint64(12312))
            coin_8 = Coin(token_bytes(32), token_bytes(32), uint64(12312))
            coin_9 = Coin(token_bytes(32), token_bytes(32), uint64(12312))
            coin_10 = Coin(token_bytes(32), token_bytes(32), uint64(12312))
            record_7 = WalletCoinRecord(coin_7, uint32(0), uint32(1), True,
                                        False, WalletType.STANDARD_WALLET, 1)
            record_8 = WalletCoinRecord(coin_8, uint32(1), uint32(2), True,
                                        False, WalletType.STANDARD_WALLET, 1)
            record_9 = WalletCoinRecord(coin_9, uint32(2), uint32(3), True,
                                        False, WalletType.STANDARD_WALLET, 1)
            record_10 = WalletCoinRecord(
                coin_10,
                uint32(3),
                uint32(4),
                True,
                False,
                WalletType.STANDARD_WALLET,
                1,
            )

            await store.add_coin_record(record_7)
            await store.add_coin_record(record_8)
            await store.add_coin_record(record_9)
            await store.add_coin_record(record_10)
            assert len(await store.get_unspent_coins_at_height(0)) == 1
            assert len(await store.get_unspent_coins_at_height(1)) == 1
            assert len(await store.get_unspent_coins_at_height(2)) == 1
            assert len(await store.get_unspent_coins_at_height(3)) == 1
            assert len(await store.get_unspent_coins_at_height(4)) == 0

            await store.add_block_record(br_2, True)
            await store.add_block_record(br_3, True)

            await store.rollback_lca_to_block(1)

            assert len(await store.get_unspent_coins_at_height(0)) == 1
            assert len(await store.get_unspent_coins_at_height(1)) == 1
            assert len(await store.get_unspent_coins_at_height(2)) == 1
            assert len(await store.get_unspent_coins_at_height(3)) == 1
            assert len(await store.get_unspent_coins_at_height(4)) == 1

        except AssertionError:
            await db_connection.close()
            raise
        await db_connection.close()
Exemplo n.º 11
0
    async def test_short_sync_with_transactions_wallet(self, wallet_node):
        full_node_1, wallet_node, server_1, server_2 = wallet_node
        wallet_a = wallet_node.wallet_state_manager.main_wallet
        wallet_a_dummy = WalletTool()
        wallet_b = WalletTool()
        coinbase_puzzlehash = await wallet_a.get_new_puzzlehash()
        coinbase_puzzlehash_rest = wallet_b.get_new_puzzlehash()
        puzzle_hashes = [
            await wallet_a.get_new_puzzlehash() for _ in range(10)
        ]
        puzzle_hashes.append(wallet_b.get_new_puzzlehash())

        blocks = bt.get_consecutive_blocks(test_constants, 3, [], 10, b"",
                                           coinbase_puzzlehash)
        for block in blocks:
            [
                _ async for _ in full_node_1.respond_block(
                    full_node_protocol.RespondBlock(block))
            ]
        await asyncio.sleep(2)
        await server_2.start_client(
            PeerInfo("localhost", uint16(server_1._port)), None)
        await asyncio.sleep(2)
        assert (wallet_node.wallet_state_manager.block_records[
            wallet_node.wallet_state_manager.lca].height == 1)
        server_2.global_connections.close_all_connections()

        dic_h = {}
        prev_coin = blocks[1].header.data.coinbase
        for i in range(11):
            pk, sk = await wallet_a.wallet_state_manager.get_keys(
                prev_coin.puzzle_hash)
            transaction_unsigned = wallet_a_dummy.generate_unsigned_transaction(
                1000, puzzle_hashes[i], prev_coin, {}, 0, secretkey=sk)
            spend_bundle = await wallet_a.sign_transaction(transaction_unsigned
                                                           )
            block_spendbundle = SpendBundle.aggregate([spend_bundle])
            program = best_solution_program(block_spendbundle)
            aggsig = block_spendbundle.aggregated_signature
            prev_coin = Coin(prev_coin.name(), puzzle_hashes[i], uint64(1000))
            dic_h[i + 4] = (program, aggsig)

        blocks = bt.get_consecutive_blocks(test_constants, 13, blocks, 10, b"",
                                           coinbase_puzzlehash_rest, dic_h)
        # Move chain to height 16, with consecutive transactions in blocks 4 to 14
        for block in blocks:
            async for _ in full_node_1.respond_block(
                    full_node_protocol.RespondBlock(block)):
                pass

        # Do a short sync from 0 to 14
        await server_2.start_client(
            PeerInfo("localhost", uint16(server_1._port)), None)
        start = time.time()
        broke = False
        while time.time() - start < 60:
            if (wallet_node.wallet_state_manager.block_records[
                    wallet_node.wallet_state_manager.lca].height >=
                    14  # Tip at 16, LCA at 14
                ):
                broke = True
                break
            await asyncio.sleep(0.1)
        if not broke:
            raise Exception(
                f"Took too long to process blocks, stopped at: {time.time() - start}"
            )

        server_2.global_connections.close_all_connections()

        # 2 block rewards and 3 fees
        assert await wallet_a.get_confirmed_balance() == (
            blocks[1].header.data.coinbase.amount *
            2) + (blocks[1].header.data.fees_coin.amount * 3)
        # All of our coins are spent and puzzle hashes present
        for puzzle_hash in puzzle_hashes[:-1]:
            records = await wallet_node.wallet_state_manager.wallet_store.get_coin_records_by_puzzle_hash(
                puzzle_hash)
            assert len(records) == 1
            assert records[0].spent and not records[0].coinbase

        # Then do the same but in a reorg chain
        dic_h = {}
        prev_coin = blocks[1].header.data.coinbase
        for i in range(11):
            pk, sk = await wallet_a.wallet_state_manager.get_keys(
                prev_coin.puzzle_hash)
            transaction_unsigned = wallet_a_dummy.generate_unsigned_transaction(
                1000, puzzle_hashes[i], prev_coin, {}, 0, secretkey=sk)
            spend_bundle = await wallet_a.sign_transaction(transaction_unsigned
                                                           )
            block_spendbundle = SpendBundle.aggregate([spend_bundle])
            program = best_solution_program(block_spendbundle)
            aggsig = block_spendbundle.aggregated_signature
            prev_coin = Coin(prev_coin.name(), puzzle_hashes[i], uint64(1000))
            dic_h[i + 4] = (program, aggsig)

        blocks = bt.get_consecutive_blocks(
            test_constants,
            31,
            blocks[:4],
            10,
            b"this is a reorg",
            coinbase_puzzlehash_rest,
            dic_h,
        )

        # Move chain to height 34, with consecutive transactions in blocks 4 to 14
        for block in blocks:
            async for _ in full_node_1.respond_block(
                    full_node_protocol.RespondBlock(block)):
                pass

        # Do a sync from 0 to 22
        await server_2.start_client(
            PeerInfo("localhost", uint16(server_1._port)), None)

        broke = False
        while time.time() - start < 60:
            if (wallet_node.wallet_state_manager.block_records[
                    wallet_node.wallet_state_manager.lca].height >=
                    28  # Tip at 34, LCA at least 28
                ):
                broke = True
                break
            await asyncio.sleep(0.1)
        if not broke:
            raise Exception(
                f"Took too long to process blocks, stopped at: {time.time() - start}"
            )
        server_2.global_connections.close_all_connections()

        # 2 block rewards and 3 fees
        assert await wallet_a.get_confirmed_balance() == (
            blocks[1].header.data.coinbase.amount *
            2) + (blocks[1].header.data.fees_coin.amount * 3)
        # All of our coins are spent and puzzle hashes present
        for puzzle_hash in puzzle_hashes[:-1]:
            records = await wallet_node.wallet_state_manager.wallet_store.get_coin_records_by_puzzle_hash(
                puzzle_hash)
            assert len(records) == 1
            assert records[0].spent and not records[0].coinbase

        # Test spending the rewards earned in reorg
        new_coinbase_puzzlehash = await wallet_a.get_new_puzzlehash()
        another_puzzlehash = await wallet_a.get_new_puzzlehash()

        dic_h = {}
        pk, sk = await wallet_a.wallet_state_manager.get_keys(
            new_coinbase_puzzlehash)
        coinbase_coin = create_coinbase_coin(25, new_coinbase_puzzlehash,
                                             uint64(14000000000000))
        transaction_unsigned = wallet_a_dummy.generate_unsigned_transaction(
            7000000000000,
            another_puzzlehash,
            coinbase_coin, {},
            0,
            secretkey=sk)
        spend_bundle = await wallet_a.sign_transaction(transaction_unsigned)
        block_spendbundle = SpendBundle.aggregate([spend_bundle])
        program = best_solution_program(block_spendbundle)
        aggsig = block_spendbundle.aggregated_signature
        dic_h[26] = (program, aggsig)

        # Farm a block (25) to ourselves
        blocks = bt.get_consecutive_blocks(
            test_constants,
            1,
            blocks[:25],
            10,
            b"this is yet another reorg",
            new_coinbase_puzzlehash,
        )

        # Brings height up to 40, with block 31 having half our reward spent to us
        blocks = bt.get_consecutive_blocks(
            test_constants,
            15,
            blocks,
            10,
            b"this is yet another reorg more blocks",
            coinbase_puzzlehash_rest,
            dic_h,
        )
        for block in blocks:
            async for _ in full_node_1.respond_block(
                    full_node_protocol.RespondBlock(block)):
                pass

        await server_2.start_client(
            PeerInfo("localhost", uint16(server_1._port)), None)

        broke = False
        while time.time() - start < 60:
            if (wallet_node.wallet_state_manager.block_records[
                    wallet_node.wallet_state_manager.lca].height >=
                    38  # Tip at 40, LCA at 38
                ):
                broke = True
                break
            await asyncio.sleep(0.1)
        if not broke:
            raise Exception(
                f"Took too long to process blocks, stopped at: {time.time() - start}"
            )
        # 2 block rewards and 4 fees, plus 7000000000000 coins
        assert (await wallet_a.get_confirmed_balance() ==
                (blocks[1].header.data.coinbase.amount * 2) +
                (blocks[1].header.data.fees_coin.amount * 4) + 7000000000000)
        records = await wallet_node.wallet_state_manager.wallet_store.get_coin_records_by_puzzle_hash(
            new_coinbase_puzzlehash)
        # Fee and coinbase
        assert len(records) == 2
        assert records[0].spent != records[1].spent
        assert records[0].coinbase == records[1].coinbase
        records = await wallet_node.wallet_state_manager.wallet_store.get_coin_records_by_puzzle_hash(
            another_puzzlehash)
        assert len(records) == 1
        assert not records[0].spent
        assert not records[0].coinbase
Exemplo n.º 12
0
    async def rl_generate_signed_aggregation_transaction(
        self, rl_info: RLInfo, consolidating_coin: Coin, rl_parent: Coin, rl_coin: Coin
    ):
        if (
            rl_info.limit is None
            or rl_info.interval is None
            or rl_info.limit is None
            or rl_info.interval is None
            or rl_info.user_pubkey is None
            or rl_info.admin_pubkey is None
        ):
            raise Exception("One ore more of the elements of rl_info is None")

        list_of_coinsolutions = []

        pubkey, secretkey = await self.get_keys(self.rl_coin_record.coin.puzzle_hash)
        # Spend wallet coin
        puzzle = rl_puzzle_for_pk(
            rl_info.user_pubkey,
            rl_info.limit,
            rl_info.interval,
            rl_info.rl_origin,
            rl_info.admin_pubkey,
        )

        solution = rl_make_solution_mode_2(
            rl_coin.puzzle_hash,
            consolidating_coin.parent_coin_info,
            consolidating_coin.puzzle_hash,
            consolidating_coin.amount,
            rl_coin.parent_coin_info,
            rl_coin.amount,
            rl_parent.amount,
            rl_parent.parent_coin_info,
        )

        signature = secretkey.sign(solution.get_hash())
        list_of_coinsolutions.append(
            CoinSolution(self.rl_coin_record.coin, Program.to([puzzle, solution]))
        )

        # Spend consolidating coin
        puzzle = rl_make_aggregation_puzzle(self.rl_coin_record.coin.puzzle_hash)
        solution = rl_make_aggregation_solution(
            consolidating_coin.name(),
            self.rl_coin_record.coin.parent_coin_info,
            self.rl_coin_record.coin.amount,
        )
        list_of_coinsolutions.append(
            CoinSolution(consolidating_coin, Program.to([puzzle, solution]))
        )
        # Spend lock
        puzstring = (
            "(r (c (q 0x"
            + hexlify(consolidating_coin.name()).decode("ascii")
            + ") (q ())))"
        )

        puzzle = Program(binutils.assemble(puzstring))
        solution = Program(binutils.assemble("()"))
        list_of_coinsolutions.append(
            CoinSolution(
                Coin(self.rl_coin_record.coin, puzzle.get_hash(), uint64(0)),
                Program.to([puzzle, solution]),
            )
        )

        aggsig = AugSchemeMPL.aggregate([signature])

        return SpendBundle(list_of_coinsolutions, aggsig)
Exemplo n.º 13
0
    async def generate_zero_val_coin(self, send=True, exclude: List[Coin] = None) -> SpendBundle:
        if self.cc_info.my_genesis_checker is None:
            raise ValueError("My genesis checker is None")
        if exclude is None:
            exclude = []
        coins = await self.standard_wallet.select_coins(0, exclude)

        assert coins != set()

        origin = coins.copy().pop()
        origin_id = origin.name()

        cc_inner = await self.get_new_inner_hash()
        cc_puzzle_hash: Program = cc_puzzle_hash_for_inner_puzzle_hash(
            CC_MOD, self.cc_info.my_genesis_checker, cc_inner
        )

        tx: TransactionRecord = await self.standard_wallet.generate_signed_transaction(
            uint64(0), cc_puzzle_hash, uint64(0), origin_id, coins
        )
        assert tx.spend_bundle is not None
        full_spend: SpendBundle = tx.spend_bundle
        self.log.info(f"Generate zero val coin: cc_puzzle_hash is {cc_puzzle_hash}")

        # generate eve coin so we can add future lineage_proofs even if we don't eve spend
        eve_coin = Coin(origin_id, cc_puzzle_hash, uint64(0))

        await self.add_lineage(
            eve_coin.name(),
            Program.to(
                (
                    1,
                    [eve_coin.parent_coin_info, cc_inner, eve_coin.amount],
                )
            ),
        )
        await self.add_lineage(eve_coin.parent_coin_info, Program.to((0, [origin.as_list(), 1])))

        if send:
            regular_record = TransactionRecord(
                confirmed_at_height=uint32(0),
                created_at_time=uint64(int(time.time())),
                to_puzzle_hash=cc_puzzle_hash,
                amount=uint64(0),
                fee_amount=uint64(0),
                confirmed=False,
                sent=uint32(10),
                spend_bundle=full_spend,
                additions=full_spend.additions(),
                removals=full_spend.removals(),
                wallet_id=uint32(1),
                sent_to=[],
                trade_id=None,
                type=uint32(TransactionType.INCOMING_TX.value),
                name=token_bytes(),
            )
            cc_record = TransactionRecord(
                confirmed_at_height=uint32(0),
                created_at_time=uint64(int(time.time())),
                to_puzzle_hash=cc_puzzle_hash,
                amount=uint64(0),
                fee_amount=uint64(0),
                confirmed=False,
                sent=uint32(0),
                spend_bundle=full_spend,
                additions=full_spend.additions(),
                removals=full_spend.removals(),
                wallet_id=self.id(),
                sent_to=[],
                trade_id=None,
                type=uint32(TransactionType.INCOMING_TX.value),
                name=full_spend.name(),
            )
            await self.wallet_state_manager.add_transaction(regular_record)
            await self.wallet_state_manager.add_pending_transaction(cc_record)

        return full_spend
Exemplo n.º 14
0
    async def coin_added(
        self,
        coin: Coin,
        coinbase: bool,
        fee_reward: bool,
        wallet_id: uint32,
        wallet_type: WalletType,
        height: uint32,
    ):
        """
        Adding coin to DB
        """
        self.log.info(f"Adding coin: {coin} at {height}")
        farm_reward = False
        if coinbase or fee_reward:
            farm_reward = True
            now = uint64(int(time.time()))
            if coinbase:
                tx_type: int = TransactionType.COINBASE_REWARD.value
            else:
                tx_type = TransactionType.FEE_REWARD.value
            tx_record = TransactionRecord(
                confirmed_at_height=uint32(height),
                created_at_time=now,
                to_puzzle_hash=coin.puzzle_hash,
                amount=coin.amount,
                fee_amount=uint64(0),
                confirmed=True,
                sent=uint32(0),
                spend_bundle=None,
                additions=[coin],
                removals=[],
                wallet_id=wallet_id,
                sent_to=[],
                trade_id=None,
                type=uint32(tx_type),
                name=coin.name(),
            )
            await self.tx_store.add_transaction_record(tx_record)
        else:
            records = await self.tx_store.tx_with_addition_coin(
                coin.name(), wallet_id)

            if len(records) > 0:
                # This is the change from this transaction
                for record in records:
                    if record.confirmed is False:
                        await self.tx_store.set_confirmed(record.name, height)
            else:
                now = uint64(int(time.time()))
                tx_record = TransactionRecord(
                    confirmed_at_height=uint32(height),
                    created_at_time=now,
                    to_puzzle_hash=coin.puzzle_hash,
                    amount=coin.amount,
                    fee_amount=uint64(0),
                    confirmed=True,
                    sent=uint32(0),
                    spend_bundle=None,
                    additions=[coin],
                    removals=[],
                    wallet_id=wallet_id,
                    sent_to=[],
                    trade_id=None,
                    type=uint32(TransactionType.INCOMING_TX.value),
                    name=coin.name(),
                )
                if coin.amount > 0:
                    await self.tx_store.add_transaction_record(tx_record)

        coin_record: WalletCoinRecord = WalletCoinRecord(
            coin, height, uint32(0), False, farm_reward, wallet_type,
            wallet_id)
        await self.coin_store.add_coin_record(coin_record)

        if wallet_type == WalletType.COLOURED_COIN:
            wallet: CCWallet = self.wallets[wallet_id]
            header_hash: bytes32 = self.blockchain.height_to_hash(height)
            block: Optional[
                HeaderBlockRecord] = await self.block_store.get_header_block_record(
                    header_hash)
            assert block is not None
            assert block.removals is not None
            await wallet.coin_added(coin, header_hash, block.removals, height)

        self.state_changed("coin_added", wallet_id)
Exemplo n.º 15
0
    async def test_short_sync_with_transactions_wallet(self, wallet_node):
        BURN_PUZZLE_HASH_1 = b"0" * 32
        BURN_PUZZLE_HASH_2 = b"1" * 32
        full_node_1, wallet_node, server_1, server_2 = wallet_node
        wallet_a = wallet_node.wallet_state_manager.main_wallet
        coinbase_puzzlehash = await wallet_a.get_new_puzzlehash()
        coinbase_puzzlehash_rest = BURN_PUZZLE_HASH_1
        puzzle_hashes = [
            await wallet_a.get_new_puzzlehash() for _ in range(10)
        ]
        puzzle_hashes.append(BURN_PUZZLE_HASH_2)

        blocks = bt.get_consecutive_blocks(test_constants, 3, [], 10, b"",
                                           coinbase_puzzlehash)
        for block in blocks:
            [
                _ async for _ in full_node_1.respond_block(
                    full_node_protocol.RespondBlock(block))
            ]
        await server_2.start_client(
            PeerInfo("localhost", uint16(server_1._port)), None)
        await time_out_assert(60, wallet_height_at_least, True, wallet_node, 1)

        server_2.global_connections.close_all_connections()

        dic_h = {}
        prev_coin = blocks[1].get_coinbase()
        for i in range(11):
            pk, sk = await wallet_a.wallet_state_manager.get_keys(
                prev_coin.puzzle_hash)
            transaction_unsigned = await wallet_a.generate_unsigned_transaction(
                1000, puzzle_hashes[i], coins=[prev_coin])
            spend_bundle = await wallet_a.sign_transaction(transaction_unsigned
                                                           )
            block_spendbundle = SpendBundle.aggregate([spend_bundle])
            program = best_solution_program(block_spendbundle)
            aggsig = block_spendbundle.aggregated_signature
            prev_coin = Coin(prev_coin.name(), puzzle_hashes[i], uint64(1000))
            dic_h[i + 4] = (program, aggsig)

        blocks = bt.get_consecutive_blocks(test_constants, 13, blocks, 10, b"",
                                           coinbase_puzzlehash_rest, dic_h)
        # Move chain to height 16, with consecutive transactions in blocks 4 to 14
        for block in blocks:
            async for _ in full_node_1.respond_block(
                    full_node_protocol.RespondBlock(block)):
                pass

        # Do a short sync from 0 to 14
        await server_2.start_client(
            PeerInfo("localhost", uint16(server_1._port)), None)
        await time_out_assert(60, wallet_height_at_least, True, wallet_node,
                              14)

        server_2.global_connections.close_all_connections()

        # 3 block rewards and 3 fees - 1000 coins spent
        assert (await wallet_a.get_confirmed_balance() ==
                (blocks[1].get_coinbase().amount * 3) +
                (blocks[1].get_fees_coin().amount * 3) - 1000)
        # All of our coins are spent and puzzle hashes present
        for puzzle_hash in puzzle_hashes[:-1]:
            records = await wallet_node.wallet_state_manager.wallet_store.get_coin_records_by_puzzle_hash(
                puzzle_hash)
            assert len(records) == 1
            assert records[0].spent and not records[0].coinbase

        # Then do the same but in a reorg chain
        dic_h = {}
        prev_coin = blocks[1].get_coinbase()
        for i in range(11):
            pk, sk = await wallet_a.wallet_state_manager.get_keys(
                prev_coin.puzzle_hash)
            transaction_unsigned = await wallet_a.generate_unsigned_transaction(
                1000,
                puzzle_hashes[i],
                coins=[prev_coin],
            )
            spend_bundle = await wallet_a.sign_transaction(transaction_unsigned
                                                           )
            block_spendbundle = SpendBundle.aggregate([spend_bundle])
            program = best_solution_program(block_spendbundle)
            aggsig = block_spendbundle.aggregated_signature
            prev_coin = Coin(prev_coin.name(), puzzle_hashes[i], uint64(1000))
            dic_h[i + 4] = (program, aggsig)

        blocks = bt.get_consecutive_blocks(
            test_constants,
            31,
            blocks[:4],
            10,
            b"this is a reorg",
            coinbase_puzzlehash_rest,
            dic_h,
        )

        # Move chain to height 34, with consecutive transactions in blocks 4 to 14
        for block in blocks:
            async for _ in full_node_1.respond_block(
                    full_node_protocol.RespondBlock(block)):
                pass

        # Do a sync from 0 to 22
        await server_2.start_client(
            PeerInfo("localhost", uint16(server_1._port)), None)

        await time_out_assert(60, wallet_height_at_least, True, wallet_node,
                              28)
        server_2.global_connections.close_all_connections()

        # 3 block rewards and 3 fees - 1000 coins spent
        assert (await wallet_a.get_confirmed_balance() ==
                (blocks[1].get_coinbase().amount * 3) +
                (blocks[1].get_fees_coin().amount * 3) - 1000)
        # All of our coins are spent and puzzle hashes present
        for puzzle_hash in puzzle_hashes[:-1]:
            records = await wallet_node.wallet_state_manager.wallet_store.get_coin_records_by_puzzle_hash(
                puzzle_hash)
            assert len(records) == 1
            assert records[0].spent and not records[0].coinbase

        # Test spending the rewards earned in reorg
        new_coinbase_puzzlehash = await wallet_a.get_new_puzzlehash()
        another_puzzlehash = await wallet_a.get_new_puzzlehash()

        dic_h = {}
        pk, sk = await wallet_a.wallet_state_manager.get_keys(
            new_coinbase_puzzlehash)
        coinbase_coin = create_coinbase_coin(uint32(25),
                                             new_coinbase_puzzlehash,
                                             uint64(14000000000000))
        transaction_unsigned = await wallet_a.generate_unsigned_transaction(
            7000000000000,
            another_puzzlehash,
            coins=[coinbase_coin],
        )
        spend_bundle = await wallet_a.sign_transaction(transaction_unsigned)
        block_spendbundle = SpendBundle.aggregate([spend_bundle])
        program = best_solution_program(block_spendbundle)
        aggsig = block_spendbundle.aggregated_signature
        dic_h[26] = (program, aggsig)

        # Farm a block (25) to ourselves
        blocks = bt.get_consecutive_blocks(
            test_constants,
            1,
            blocks[:25],
            10,
            b"this is yet another reorg",
            new_coinbase_puzzlehash,
        )

        # Brings height up to 40, with block 31 having half our reward spent to us
        blocks = bt.get_consecutive_blocks(
            test_constants,
            15,
            blocks,
            10,
            b"this is yet another reorg more blocks",
            coinbase_puzzlehash_rest,
            dic_h,
        )
        for block in blocks:
            async for _ in full_node_1.respond_block(
                    full_node_protocol.RespondBlock(block)):
                pass

        await server_2.start_client(
            PeerInfo("localhost", uint16(server_1._port)), None)
        await time_out_assert(60, wallet_height_at_least, True, wallet_node,
                              38)

        # 4 block rewards and 4 fees - 1000 coins spent
        assert (await wallet_a.get_confirmed_balance() ==
                (blocks[1].get_coinbase().amount * 4) +
                (blocks[1].get_fees_coin().amount * 4) - 1000)
        records = await wallet_node.wallet_state_manager.wallet_store.get_coin_records_by_puzzle_hash(
            new_coinbase_puzzlehash)
        # Fee and coinbase
        assert len(records) == 2
        print(records)
        assert records[0].spent != records[1].spent
        assert records[0].coinbase == records[1].coinbase
        records = await wallet_node.wallet_state_manager.wallet_store.get_coin_records_by_puzzle_hash(
            another_puzzlehash)
        assert len(records) == 1
        assert not records[0].spent
        assert not records[0].coinbase