从 sCrypt 智能合约中访问区块链数据(2)

上一篇文章中,我们介绍了一种以最小信任访问块和其中的交易的方法。
本文中, 我们将其扩展为在包含多个区块。使用该技术,我们基于区块时间开发了一个简单的投注合约。我们还展示了另一种阻止伪造块的方法。

在这里插入图片描述

一个由 3 个区块组成的序列

多个区块组成的序列

如下所示,isBlockHeaderValid() 验证一个区块序列,而不是我们在上一篇文章中所做的单个区块。我们在第 8 行重用现有代码中的函数 isBlockHeaderValid() 来验证每个单独的块。此外,我们在第 12 行对区块头进行哈希处理,并确保哈希与第 14 行的下一个区块头中的 prevBlockHash 字段匹配。

// is a chain of block headers valid
static function isBlockHeaderChainValid(static const int N, BlockHeader[N] headers, int blockchainTarget) : bool {
    bool res = true;

    loop (N) : i {
        if (res) {
            // each block is valid
            if (!isBlockHeaderValid(headers[i], blockchainTarget))
                res = false;

            if (i > 0) {
                Sha256 prevBlockHash = blockHeaderHash(headers[i - 1]);
                // blocks are chained
                if (prevBlockHash != headers[i].prevBlockHash)
                    res = false; 
            }
        }
    }

    return res;
}
Blockchain 源代码

也就是说,验证了这两个块是链接在一起的。

案例研究:押注出块时间

平均而言,在比特币上产生一个区块需要 10 分钟。Alice 和 Bob 想打赌挖掘特定区块需要多长时间。他们每个人都在一个包含了以下智能合约的交易中锁定了一些 BSV。交易广播后,将被处理打包进一个区块。如果该区块的产生时间少于 10 分钟,则 Alice 获胜并拿走所有锁定的 BSV;否则,鲍勃获胜。我们使用块的时间戳(标头中的第 4 个字段)与其前一个块的时间戳之间的差异作为出块时间¹。

// bet on block time: how long it takes to mine the block containing the bet transaction
contract BlockTimeBet {
    // only 2 is needed; 7 means the transaction has 6 confirmations
    static const int N = 7;
    // 10 minutes in seconds
    static const int AVG_BLOCK_TIME = 600;
    // maximal target for any block to be considered valid
    int blockchainTarget;

    PubKey alice;
    PubKey bob;


    // header[1] is the block containing the contract tx
    public function main(BlockHeader[N] headers, MerkleProof merkleproof, Sig sig,  SigHashPreimage txPreimage) {
        require(Tx.checkPreimage(txPreimage));

        // get id of previous tx
        Sha256 prevTxid = Sha256(SigHash.outpoint(txPreimage)[:32]);

        // validate a chain of block headers
        require(Blockchain.isBlockHeaderChainValid(N, headers, this.blockchainTarget));

        // verify previous tx is in block with index 1
        require(Blockchain.txInBlock(prevTxid, headers[1], merkleproof));

        // block time is the time difference between this block and last
        int blockTime = headers[1].time - headers[0].time;

        // Alice wins if block is mined within 10 mins; otherwise Bob wins
        PubKey winner = blockTime < AVG_BLOCK_TIME ? this.alice : this.bob;
        require(checkSig(sig, winner));
    }
}
BlockTimeBet 合约源代码

与上一篇文章的 BlockchainPRNG 合约一样,我们使用 OP_PUSH_TX 技术 来获取包含投注合约的交易的 txid 。第 22 行验证区块头链是否合法,第 25 行验证投注交易在其中。第 28 行计算出块时间,用于在第 31 行确定获胜者。

鉴别假块

在上一篇文章中,我们引入了 blockchainTarget 参数来控制可接受的区块头的难度。我们还可以要求在一个区块之上构建多个区块,从而使导入假的区块数据变得更加困难。要求的区块越多,伪造它的成本就越高。这类似于使用比特币购买商品时所需的 6 次确认。在上面的投注合约中,我们只需要将 N 改为 7 即可确保包含该合约的交易有 6 个确认。

附录

[1]: 比特币区块时间戳不精确,通常不能用于衡量 10 分钟的时间间隔。但只要它是随机且难以预测的,投注合约就可以,因为它依赖于区块时间的随机性,而不是其精度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sCrypt Web3应用开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值