如何正确地使不可替代的代币独一无二

How to properly make NonFungibleToken's Unique

问题:

用于构建 NonFungibleTokenTokenTypeTokenIdentifier 是否必须是唯一的字符串?

啰嗦背景:

documentation 明确指出“事实上,开发人员有责任确保 NonFungibleToken 的两个实例不指向同一个链下或链上对象……”

我的印象是 UniqueIdentifier 是我确保唯一性的方式:

TokenType tokenType = new TokenType("Toyota Corolla", 0);
IssuedTokenType issuedTokenType = new IssuedTokenType(partyA, tokenType);

String VIN = "1G2JB12F047226515";
UUID uuid = UUID.randomUUID();
UniqueIdentifier uniqueIdentifier = new UniqueIdentifier(VIN, uuid);

NonFungibleToken nonFungibleToken = new NonFungibleToken(issuedTokenType, partyA, uniqueIdentifier);

这让我可以定义无限的 Toyota Corolla,每个都有自己独特的 UUID 和车辆识别码 (VIN)。

MoveNonFungibleTokens() 流程允许我指定 QueryCriteria 来隔离我希望移动的特定 NonFungibleToken(我使用 LinearStateQueryCriteria 指定 UUID):

subFlow(new MoveNonFungibleTokens(partyAndToken, observers, queryCriteria));

然而,当我想兑换 NonFungibleToken 时,RedeemNonFungibleTokens() 流程只允许我指定 TokenType:

subFlow(new RedeemNonFungibleTokens(tokenType, issuer, observers));

这意味着我无法通过 UUID 来识别 NonFungibleToken。如果您按照我上面的操作进行操作,您将在我尝试兑换时收到以下错误消息:

Exactly one held token of a particular type TokenType(tokenIdentifier=' Toyota Corolla ', fractionDigits=0) should be in the vault at any one time.

如果是这样,那么TokenTypetokenIndentifier(“Toyota Corolla”)一定是独一无二的来源。我将不得不做这样的事情:

TokenType tokenType = new TokenType("Toyota Corolla-" + UUID.randomUUID(), 0);

这是正确的还是我错过了什么?

当我开始编写令牌测试的兑换部分时,我真的很惊讶,我想“那么 NonFungibleTokenUniqueIdentifier 的目的是什么?”

  • 在non-fungible个令牌的情况下,令牌类型和令牌之间的关系是一对一;这就是为什么兑换流程只需要 TokenType 参数。
  • 查看 MoveNonFungibleTokens 流输入参数 here,它们与第一个陈述有点矛盾;因为即使对流程的评论也指出它应该一次用于一个 TokenType,这意味着不需要 queryCriteria 参数,因为您已经指定了您的令牌(令牌类型)想要在 PartyAndToken 参数内移动。我会将此讨论转发给 R3 工程师以获得澄清。
  • 至于您的问题,您需要 non-fungible 令牌中的唯一标识符的原因是因为它扩展了 LinearState(由 UUID 标识)。
  • 请记住,Corda 中的状态是不可变的,那么您如何模拟更新?您使用 LinearState 购买,例如,如果您的 non-fungible 代币是一辆汽车,并且您想更改汽车的所有者(即更新代币的 holder);然后创建一个交易,其中输入是当前代币,输出是更新后的代币,它应该与输入具有相同的 linearId;通过这种方式,输出和输入被绑定在一起,现在您可以通过查询共享 linearId.
  • 来跟踪特定状态的更新历史
  • 旁注:您的 LinearState 应该有 2 个构造函数;一个分配随机 linearId 的构造函数,您应该在创建新状态时使用它,另一个构造函数将 linearId 作为输入参数;当你创建更新事务的输出时应该使用这个构造函数(这样你就可以用输入的 linearId 创建输出),你也必须用 @CordaSerializable 注释标记那个构造函数,这样 Corda当它 check-points 某个流时使用它(即序列化然后 de-serializes 你的状态)否则 Corda 将使用另一个构造函数并为你的 linearId 分配一个新的随机值当它 de-serializes 你的状态(当流程恢复时),你基本上以不同的状态结束!
  • 我建议您使用 EvolvableTokenType 作为汽车示例,而不是 TokenType;这将允许您添加自定义属性(VIN、价格、里程等),并且您可以控制哪些属性可以更新(价格、里程),哪些不能(VIN);在 R3 here.
  • 的官方免费 Corda 课程中查看更多相关信息