我们开发了一个基于智能合约的比特币保险库,其中锁定的比特币只能在延迟用户定义的时间后转移。
密钥盗窃是困扰比特币用户的一个主要问题。一种保护比特币的方法是将它们存储在不允许即时取款的保险库中。要花费保险库中比特币,需要两个连续的步骤。
- 通过第一笔交易发出将硬币移出金库的请求,这称为出库 (unvault)
- 等待预定义的时间, 称为出库期 (unvaulting),比如在第一笔交易入块后 24 小时,然后硬币可以在后续交易中移出。
这两个步骤都使用称为保险库密钥的密钥。另一个称为恢复密钥的密钥可以在 24 小时内阻止第二笔交易,以防保险库密钥被盗。通常,保险库密钥存储在热钱包中,而恢复密钥存储在冷钱包中。
实现
基于相对时间锁定,我们开发了以下保险库合约。
import "blockchain.scrypt";
contract Vault {
int unvaultingPeriod;
PubKey vaultKey;
PubKey recoveryKey;
int blockchainTarget;
@state
bool unvaulted;
public function unvault(Sig sig, SigHashPreimage txPreimage) {
require(checkSig(sig, this.vaultKey));
require(!this.unvaulted);
this.unvaulted = true;
bytes outputScript = this.getStateScript();
bytes output = Utils.buildOutput(outputScript, SigHash.value(txPreimage));
require(hash256(output) == SigHash.hashOutputs(txPreimage));
}
public function withdraw(Sig sig, BlockHeader utxoBh, BlockHeader latestBh, MerkleProof merkleproof, SigHashPreimage txPreimage) {
require(this.unvaulted);
require(checkSig(sig, this.vaultKey));
this.validateHelper(utxoBh, latestBh, merkleproof, txPreimage);
require(latestBh.time - utxoBh.time >= this.unvaultingPeriod);
}
public function cancel(Sig sig) {
require(checkSig(sig, this.recoveryKey));
}
}
首先,通过在交易来调用的第 18 行 unvault() 来出库锁定在合约中的硬币。它在 22 行将出库状态 unvaulted 从 false 设置为 true ,并在 24 到 26 行传播状态。如果一切顺利,在第一笔交易入块后,等待超过预设的出库期 (unvaulting) 后,通过调用 30 行的 withdraw() 来提取硬币。第 35-37 行和以前一样使用相对时间锁。如果在此期间检测到盗窃企图,则恢复密钥可以撤消交易并将硬币移动其他地方,见 41 行。
讨论
可以添加其他措施以使保险库更加安全,例如白名单或支出限制。将这个方法应用到 Token 上也很简单。
[1] : 将其扩展为持有 Token 也很简单。有一些方法可以在不运行完整节点的情况下执行此操作,例如 mAPI 中的实时通知。
|