mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2026-09-05 02:24:21 -05:00
Merge pull request #11812 from Chia-Network/nft1_did_fix
Fix DID related NFT bugs
This commit is contained in:
@@ -135,6 +135,7 @@ class WalletRpcApi:
|
||||
# NFT Wallet
|
||||
"/nft_mint_nft": self.nft_mint_nft,
|
||||
"/nft_get_nfts": self.nft_get_nfts,
|
||||
"/nft_get_by_did": self.nft_get_by_did,
|
||||
"/nft_get_info": self.nft_get_info,
|
||||
"/nft_transfer_nft": self.nft_transfer_nft,
|
||||
"/nft_add_uri": self.nft_add_uri,
|
||||
@@ -1388,6 +1389,16 @@ class WalletRpcApi:
|
||||
nft_info_list.append(nft_puzzles.get_nft_info_from_puzzle(nft))
|
||||
return {"wallet_id": wallet_id, "success": True, "nft_list": nft_info_list}
|
||||
|
||||
async def nft_get_by_did(self, request) -> Dict:
|
||||
did_id: Optional[bytes32] = None
|
||||
if "did_id" in request:
|
||||
did_id = bytes32.from_hexstr(request["did_id"])
|
||||
assert self.service.wallet_state_manager is not None
|
||||
for wallet in self.service.wallet_state_manager.wallets.values():
|
||||
if isinstance(wallet, NFTWallet) and wallet.get_did() == did_id:
|
||||
return {"wallet_id": wallet.wallet_id, "success": True}
|
||||
return {"error": f"Cannot find a NFT wallet DID = {did_id}", "success": False}
|
||||
|
||||
async def nft_transfer_nft(self, request):
|
||||
assert self.service.wallet_state_manager is not None
|
||||
wallet_id = uint32(request["wallet_id"])
|
||||
|
||||
@@ -12,7 +12,11 @@ from chia.wallet.nft_wallet.nft_info import NFTCoinInfo, NFTInfo
|
||||
from chia.wallet.nft_wallet.uncurry_nft import UncurriedNFT
|
||||
from chia.wallet.puzzles.cat_loader import CAT_MOD
|
||||
from chia.wallet.puzzles.load_clvm import load_clvm
|
||||
from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import solution_for_conditions
|
||||
from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import (
|
||||
DEFAULT_HIDDEN_PUZZLE_HASH,
|
||||
calculate_synthetic_public_key,
|
||||
solution_for_conditions,
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
SINGLETON_TOP_LAYER_MOD = load_clvm("singleton_top_layer_v1_1.clvm")
|
||||
@@ -227,7 +231,8 @@ def create_ownership_layer_transfer_solution(
|
||||
str(trade_prices_list),
|
||||
new_pubkey,
|
||||
)
|
||||
puzhash = STANDARD_PUZZLE_MOD.curry(new_pubkey).get_tree_hash()
|
||||
synthetic_pk: bytes = bytes(calculate_synthetic_public_key(new_pubkey, DEFAULT_HIDDEN_PUZZLE_HASH))
|
||||
puzhash: bytes32 = STANDARD_PUZZLE_MOD.curry(synthetic_pk).get_tree_hash()
|
||||
condition_list = [
|
||||
[
|
||||
51,
|
||||
@@ -235,7 +240,7 @@ def create_ownership_layer_transfer_solution(
|
||||
1,
|
||||
[puzhash],
|
||||
],
|
||||
[-10, new_did, trade_prices_list, new_pubkey, [new_did_inner_hash]],
|
||||
[-10, new_did, trade_prices_list, synthetic_pk, [new_did_inner_hash]],
|
||||
]
|
||||
log.debug("Condition list raw: %r", condition_list)
|
||||
solution = Program.to(
|
||||
|
||||
@@ -123,6 +123,7 @@ class NFTWallet:
|
||||
self.standard_wallet = wallet
|
||||
self.wallet_info = wallet_info
|
||||
self.nft_wallet_info = NFTWalletInfo.from_json_dict(json.loads(wallet_info.data))
|
||||
self.did_id = self.nft_wallet_info.did_id
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
@@ -214,7 +215,8 @@ class NFTWallet:
|
||||
derivation_record: Optional[
|
||||
DerivationRecord
|
||||
] = await self.wallet_state_manager.puzzle_store.get_derivation_record_for_puzzle_hash(p2_puzzle_hash)
|
||||
if derivation_record:
|
||||
|
||||
if derivation_record and not uncurried_nft.supports_did:
|
||||
p2_puzzle = puzzle_for_pk(derivation_record.pubkey)
|
||||
else:
|
||||
# we don't have this puzhash in puzzle store
|
||||
@@ -250,7 +252,8 @@ class NFTWallet:
|
||||
if new_coin.puzzle_hash == child_puzzle.get_tree_hash():
|
||||
child_coin = new_coin
|
||||
break
|
||||
|
||||
else:
|
||||
raise ValueError(f"Rebuild NFT doesn't match the actual puzzle hash: {child_puzzle}")
|
||||
launcher_coin_states: List[CoinState] = await self.wallet_state_manager.wallet_node.get_coin_state(
|
||||
[singleton_id]
|
||||
)
|
||||
@@ -421,13 +424,11 @@ class NFTWallet:
|
||||
|
||||
bundles_to_agg = [tx_record.spend_bundle, launcher_sb]
|
||||
|
||||
if not target_puzzle_hash:
|
||||
target_puzzle_hash = p2_inner_puzzle.get_tree_hash()
|
||||
record: Optional[DerivationRecord] = None
|
||||
# Create inner solution for eve spend
|
||||
if did_id is not None:
|
||||
record = await self.wallet_state_manager.puzzle_store.get_derivation_record_for_puzzle_hash(
|
||||
p2_inner_puzzle.get_tree_hash()
|
||||
target_puzzle_hash
|
||||
)
|
||||
self.log.debug("Got back a pubkey record: %s", record)
|
||||
if not record:
|
||||
@@ -532,7 +533,7 @@ class NFTWallet:
|
||||
additional_bundles: List[SpendBundle] = [],
|
||||
) -> TransactionRecord:
|
||||
# Update NFT status
|
||||
await self.update_coin_status(nft_coin_info.coin.name(), True)
|
||||
|
||||
coin = nft_coin_info.coin
|
||||
amount = coin.amount
|
||||
if not additional_bundles:
|
||||
@@ -596,6 +597,7 @@ class NFTWallet:
|
||||
inner_solution = Program.to([solution_for_conditions(condition_list), 1])
|
||||
nft_tx_record = await self._make_nft_transaction(nft_coin_info, inner_solution, [puzzle_hash], fee)
|
||||
await self.standard_wallet.push_transaction(nft_tx_record)
|
||||
await self.update_coin_status(nft_coin_info.coin.name(), True)
|
||||
self.wallet_state_manager.state_changed("nft_coin_updated", self.wallet_info.id)
|
||||
return nft_tx_record.spend_bundle
|
||||
|
||||
@@ -622,6 +624,7 @@ class NFTWallet:
|
||||
fee,
|
||||
)
|
||||
await self.standard_wallet.push_transaction(nft_tx_record)
|
||||
await self.update_coin_status(nft_coin_info.coin.name(), True)
|
||||
self.wallet_state_manager.state_changed("nft_coin_transferred", self.wallet_info.id)
|
||||
return nft_tx_record.spend_bundle
|
||||
|
||||
@@ -719,6 +722,7 @@ class NFTWallet:
|
||||
return await cls.create_new_nft_wallet(
|
||||
wallet_state_manager,
|
||||
wallet,
|
||||
None,
|
||||
name,
|
||||
in_transaction,
|
||||
)
|
||||
|
||||
@@ -716,19 +716,18 @@ class WalletStateManager:
|
||||
"""
|
||||
wallet_id = None
|
||||
wallet_type = None
|
||||
self.log.debug("Handling NFT: %s", coin_spend)
|
||||
did_id = uncurried_nft.owner_did
|
||||
for wallet_info in await self.get_all_wallet_info_entries():
|
||||
if wallet_info.type == WalletType.NFT:
|
||||
nft_wallet_info: NFTWalletInfo = NFTWalletInfo.from_json_dict(json.loads(wallet_info.data))
|
||||
if nft_wallet_info.did_id == did_id:
|
||||
self.log.debug(
|
||||
"Checking NFT wallet %r and inner puzzle %s",
|
||||
wallet_info.name,
|
||||
uncurried_nft.inner_puzzle.get_tree_hash(),
|
||||
)
|
||||
wallet_id = wallet_info.id
|
||||
wallet_type = WalletType.NFT
|
||||
self.log.debug("Handling NFT: %s, DID: %s", coin_spend, did_id)
|
||||
for wallet_info in await self.get_all_wallet_info_entries(wallet_type=WalletType.NFT):
|
||||
nft_wallet_info: NFTWalletInfo = NFTWalletInfo.from_json_dict(json.loads(wallet_info.data))
|
||||
if nft_wallet_info.did_id == did_id:
|
||||
self.log.debug(
|
||||
"Checking NFT wallet %r and inner puzzle %s",
|
||||
wallet_info.name,
|
||||
uncurried_nft.inner_puzzle.get_tree_hash(),
|
||||
)
|
||||
wallet_id = wallet_info.id
|
||||
wallet_type = WalletType.NFT
|
||||
|
||||
if wallet_id is None:
|
||||
self.log.info(
|
||||
@@ -748,7 +747,6 @@ class WalletStateManager:
|
||||
self, coin_states: List[CoinState], peer: WSChiaConnection, fork_height: Optional[uint32]
|
||||
) -> None:
|
||||
# TODO: add comment about what this method does
|
||||
|
||||
# Input states should already be sorted by cs_height, with reorgs at the beginning
|
||||
curr_h = -1
|
||||
for c_state in coin_states:
|
||||
|
||||
@@ -12,6 +12,7 @@ from chia.simulator.simulator_protocol import FarmNewBlockProtocol
|
||||
from chia.types.blockchain_format.program import Program
|
||||
from chia.types.blockchain_format.sized_bytes import bytes32
|
||||
from chia.types.peer_info import PeerInfo
|
||||
from chia.util.bech32m import encode_puzzle_hash
|
||||
from chia.util.byte_types import hexstr_to_bytes
|
||||
from chia.util.ints import uint16, uint32, uint64
|
||||
from chia.wallet.did_wallet.did_wallet import DIDWallet
|
||||
@@ -593,21 +594,36 @@ async def test_nft_with_did_wallet_creation(two_wallet_nodes: Any, trusted: Any)
|
||||
assert res.get("success")
|
||||
nft_wallet_p2_puzzle = res["wallet_id"]
|
||||
assert nft_wallet_p2_puzzle != nft_wallet_0_id
|
||||
|
||||
res = await api_0.nft_get_by_did({"did_id": hex_did_id})
|
||||
assert nft_wallet_0_id == res["wallet_id"]
|
||||
await time_out_assert(10, wallet_0.get_unconfirmed_balance, 5999999999999)
|
||||
await time_out_assert(10, wallet_0.get_confirmed_balance, 5999999999999)
|
||||
# Create a NFT with DID
|
||||
nft_ph: bytes32 = await wallet_0.get_new_puzzlehash()
|
||||
resp = await api_0.nft_mint_nft(
|
||||
{
|
||||
"wallet_id": nft_wallet_0_id,
|
||||
"hash": "0xD4584AD463139FA8C0D9F68F4B59F185",
|
||||
"uris": ["https://www.chia.net/img/branding/chia-logo.svg"],
|
||||
"target_address": encode_puzzle_hash(nft_ph, "txch"),
|
||||
}
|
||||
)
|
||||
assert resp.get("success")
|
||||
sb = resp["spend_bundle"]
|
||||
# ensure hints are generated correctly
|
||||
memos = compute_memos(sb)
|
||||
assert memos
|
||||
puzhashes = []
|
||||
for x in memos.values():
|
||||
puzhashes.extend(list(x))
|
||||
assert len(puzhashes) > 0
|
||||
matched = 0
|
||||
for puzhash in puzhashes:
|
||||
if puzhash.hex() == nft_ph.hex():
|
||||
matched += 1
|
||||
assert matched > 0
|
||||
|
||||
# ensure hints are generated
|
||||
assert compute_memos(sb)
|
||||
await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, sb.name())
|
||||
|
||||
for i in range(1, num_blocks):
|
||||
|
||||
Reference in New Issue
Block a user