一种 BSV 智能合约的扩展方法:支付到合约哈希

Posted sCrypt 智能合约

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一种 BSV 智能合约的扩展方法:支付到合约哈希相关的知识,希望对你有一定的参考价值。

事实证明, BSV 上的智能合约比以前想象的更强大、更通用。然而,仍然有两个严重的限制:

  1. 合约一旦部署就不能支持新功能。例如,我们可以部署一个代币合约,但后来发现由于缺乏某些功能,它无法集成到一些新的交易所或投票应用程序中。这极大地阻碍了它与第三方应用程序的互操作性,从而阻碍了它的广泛采用。

  2. 第一个限制也暗示所有受支持的功能都必须包含在代币合约中。即使我们可以预见到令牌在最初构思时需要支持的所有功能,也只有少数功能是常用的,而大多数功能很少使用。

支付到合约哈希 (Pay to Contract Hash)

我们提出了一种新颖的方法来同时解决这两个限制,称为支付到合约哈希 (P2CH)。我们以 NFT 为例来演示它是如何工作的。它也适用于其他加密资产,例如原生 BSV 和同质化代币。在我们之前的 NFT 合约中,我们维护了一个表,将每个代币映射到其所有者的地址。所有者拥有可以授权转移令牌的私钥。

图 1: NFT 3 由合约拥有

在 P2CH 下,所有者也可以是合约的地址,定义为其脚本的哈希值。哈希值作为合约的唯一 ID,用于引用合约。

具体来说,使用了 hash160,与用于将 BSV 公钥散列到地址中的散列算法相同。合约哈希看起来与普通 BSV 地址相同,因为它们都是 20 字节。新的 NFT 合约如下所示:

contract Pay2ContractHash 
    @state
    HashedMap<int, PubKeyHash> owners;

    public function transferFrom(PubKeyHash from, PubKeyHash to,    // can be hash of a user's public key, or a contract
        Sig fromSig, PubKey fromPubKey,                             // only needed when token belongs to a user controlling a private key
        bytes prevouts, bytes contractTx, int contractInputIndex,   // only needed when token belongs to a contract
        int tokenId, int keyIndex, SigHashPreimage preimage) 
        // verify ownership
        require(this.owners.canGet(tokenId, from, keyIndex));
        
        // authenticate
        if (hash160(fromPubKey) == from) 
            // belongs to a user
            require(checkSig(fromSig, fromPubKey));
         else 
            // belongs to a contract, not a user
            require(TxUtil.verifyContractByHash(
                        prevouts,
                        contractInputIndex,
                        contractTx,
                        from,
                        preimage));
        

        require(this.owners.set(tokenId, to, keyIndex));
    
        require(this.propagateState(preimage));
    


Pay2ContractHash 合约

除了 else 分支, 这与之前的 NFT 合约相同。else 分支负责处理当代币由合约而不是用户的私钥控制时的代币传输。

我们需要确保合约在同一交易的另一个输入中被解锁,就像我们在合约间调用中所做的那样。

在图 2 所示的示例中,输入 0 中引用的令牌需要验证同一交易 tx2 中的输入 1 是否引用了预期合约。

  • 20-22 行获取包含合约的交易的 id(图中的 tx1)和它包含的输出(tx1 中的输出 0
  • 24 行验证完整交易是否与 txid 匹配。
  • 26 行解析合约交易以获取合约的完整脚本并将其与第 27 行的所有者“地址”进行哈希匹配。

图 2: 转让合约拥有的代币

代币销售合约示例

一个示例合同可能如下:

contract TokenSale 
    PubKeyHash recvAddr;
    int recvAmount;

    public function unlock(SigHashPreimage txPreimage) 
        SigHashType sigHashType = SigHash.SINGLE | SigHash.FORKID;
        require(Util.checkPreimageSigHashType(txPreimage, sigHashType));

        bytes outputScript = Util.buildPublicKeyHashScript(this.recvAddr);
        bytes output = Util.buildOutput(outputScript, this.recvAmount);

        require(hash256(output) == Util.hashOutputs(txPreimage));
    

TokenSale 合约

当且仅当给定地址支付特定金额时,才能使用它。使用这个合约,我们可以通过三个步骤以给定的价格原子地出售代币:

  1. 部署 TokenSale 合约。
  2. 将代币转入上述合约的哈希,即其锁定脚本的 hash160。现在代币受合约控制,而不是用户的私钥。这类似于以太坊中的合约账户,没有对应的私钥,以太坊中用户常用的是EOA账户
  3. 在一次交易中同时解锁代币和 TokenSale 合约,如图 2 所示。买方将把代币从合约中转移给自己。

可以在此处找到完整的代码示例

总结

值得注意的是,合约可以是任意的,可以由第三方独立开发,也不必事先知道。这意味着令牌是无限可扩展的(限制 1)。此外,它结构紧凑,仅处理适用于任何合约的 P2CH(限制 2)。此外,还可以使用模式匹配合约的替代方法。上面例子我们使用完整合约脚本的哈希匹配,也可以使用部分脚本的哈希进行匹配,例如有状态合约的代码部分。

致谢

这个想法来自Sensible Contract陈诚

以上是关于一种 BSV 智能合约的扩展方法:支付到合约哈希的主要内容,如果未能解决你的问题,请参考以下文章

BSV 智能合约中的可扩展状态存储

一种灵活的智能合约协作方式

BSV 上基于智能合约的众筹

BSV 上的付费解密智能合约

BSV资讯感应合约大幅推进BSV区块链上的NFT和智能合约方案

官方发布|BSV区块链协会推出全新智能合约转译器