上一篇文章介绍了Bitcoin Computer的基本原理和特点,本文介绍Bitcoin Computer如何对比特币进行操作。
Bitcoin Computer的合约还有一个保留成员变量_amount
。这个成员变量用于控制合约所在输出的比特币数量,单位为聪。结合上一篇讲到的另一个保留成员变量_owners
,就可以实现比特币转账了。
钞票合约解析
我们来看一个钞票合约的例子。
import Computer from 'bitcoin-computer';
class Cash {
constructor(amount) {
this._amount = amount
}
transfer(to) {
this._owners = [to]
}
}
(async () => {
const computerA = new Computer.default({
seed: 'the mnemonic words',
chain: 'BSV',
network: 'testnet'
});
const computerB = new Computer.default({
seed: 'different mnemonic words',
chain: 'BSV',
network: 'testnet'
});
let cash = await computerA.new(Cash, [1000]);
console.log(cash);
await cash.transfer(computerB.db.wallet.getPublicKey().toString());
console.log(cash);
cash = await computerB.sync(cash._rev);
await cash.transfer(computerA.db.wallet.getPublicKey().toString());
console.log(cash);
})();
- 定义一个钞票合约。构造函数的参数对
_amount
进行初始化,这在合约部署时确定了对应output的聪数。transfer
方法相当于把钞票的使用权转给谁。 - 用两组不同的助记词定义两个
Computer
实例,用于更换钞票的所属权。 - 用
computerA
部署合约,面额1000聪,此时所属权归computerA
。 - 调用
transfer
方法把钞票所有权转给computerB
。 computerB
把合约同步下来,再转回给computerA
。
合约部署之后的cash
变量值如下:
Cash {
_amount: 1000,
_id: '3323850d869658f5a89b832d359c1cbb308caa3ff2a4e19c28e837878a8f31ad:0',
_rev: '3323850d869658f5a89b832d359c1cbb308caa3ff2a4e19c28e837878a8f31ad:0',
_rootId: '3323850d869658f5a89b832d359c1cbb308caa3ff2a4e19c28e837878a8f31ad:0'
}
_amount
变量的值为1000,那么该输出里也应该有1000聪。查看区块浏览器,发现确实如此。
另外,脚本输出中多签名的公钥为03367b59cc6ba5cdb93b3bdc61c7018655462251b3608383c5a1b4adcf5f1bcc1f
。同时javascript创建实例的代码也附在了脚本中,上一篇文章中我们已经解释过了。
computerA
调用transfer
方法后,cash
变量值如下:
Cash {
_amount: 1000,
_id: '3323850d869658f5a89b832d359c1cbb308caa3ff2a4e19c28e837878a8f31ad:0',
_rev: '2db31d5718b491d5bfb69c8acdf7b952571c547653020f2d5b382fdd00156b12:0',
_rootId: '3323850d869658f5a89b832d359c1cbb308caa3ff2a4e19c28e837878a8f31ad:0',
_owners: [
'02c9788a60264523ba77500e19a0b2626c9b09b25daa16cfee09b4e1135d610c90'
]
}
查看区块链浏览器,合约输出里依然保持了1000聪,但多签名的公钥已经改为02c9788a60264523ba77500e19a0b2626c9b09b25daa16cfee09b4e1135d610c90
,相当于解锁权已经给了computerB
。
computerB
把合约数据同步过来,再调用transfer
方法转给computerA
。cash
变量值如下:
Cash {
_amount: 1000,
_rev: '258f09ca6649a4c7e1e980df2e1bf7467f48b815b3008fcc4701730c6ab66837:0',
_id: '3323850d869658f5a89b832d359c1cbb308caa3ff2a4e19c28e837878a8f31ad:0',
_rootId: '3323850d869658f5a89b832d359c1cbb308caa3ff2a4e19c28e837878a8f31ad:0',
_owners: [
'03367b59cc6ba5cdb93b3bdc61c7018655462251b3608383c5a1b4adcf5f1bcc1f'
]
}
查看区块链浏览器,合约输出还是1000聪,多签名的公钥又改回了03367b59cc6ba5cdb93b3bdc61c7018655462251b3608383c5a1b4adcf5f1bcc1f
,相当于解锁权又还给了computerA
。
通过这样一个合约,大家就理解_amount
的作用了:决定合约输出的聪数。
合约手续费
大家可能会有个疑问,1000聪转来转去没变,那转账手续费是谁出的?可以在区块浏览器中查看前面几笔转账,观察可以发现,手续费是由执行合约的Computer
示例出的。即:
- 合约部署时,由
computerA
出手续费。同时也出了1000聪放到合约输出中。出钱的地址为mjg7nQ4VuJ3rTws8QFAD3NMMs1YgtzDm7C
,也就是公钥03367b59cc6ba5cdb93b3bdc61c7018655462251b3608383c5a1b4adcf5f1bcc1f
对应的地址。 computerA
调用合约的transfer
方法时,手续费也是从自己的地址mjg7nQ4VuJ3rTws8QFAD3NMMs1YgtzDm7C
出的。computerB
调用合约的transfer
方法是,手续费从computerB
的地址mpkhoZmfrxAAnU5mAv5yKcY83pYqWxh6jT
转出,也就是公钥02c9788a60264523ba77500e19a0b2626c9b09b25daa16cfee09b4e1135d610c90
对应的地址。
也就是说,手续费是由执行合约的Computer
实例的P2PKH地址出。
从合约转出部分比特币
前面我用把1000聪面额的cash
全面额转出,那是否可以部分转出呢?也是可以的。我们看如下程序:
import Computer from 'bitcoin-computer';
class Cash {
constructor(amount) {
this._amount = amount
}
transfer(amount, to) {
this._amount = amount;
this._owners = [to]
}
}
(async () => {
const computerA = new Computer.default({
seed: 'the mnemonic words',
chain: 'BSV',
network: 'testnet'
});
const computerB = new Computer.default({
seed: 'different mnemonic words',
chain: 'BSV',
network: 'testnet'
});
let cash = await computerA.new(Cash, [2000]);
await cash.transfer(1000, computerB.db.wallet.getPublicKey().toString());
console.log(cash);
})();
对Cash
合约的代码进行了改进,transfer
方法允许携带amount
参数来明确转多少聪。
computerA
向合约中部署了2000聪,但只转给了computerB
1000聪,通过区块链浏览器可以看到,这次transfer
执行操作的tx把剩下的币转到了computerA
控制的地址mjg7nQ4VuJ3rTws8QFAD3NMMs1YgtzDm7C
中,也就是说转到了合约执行者的地址。
同时,还可以看到,这笔转账的手续费是从部署到合约中的2000聪里出的。
总结
Bitcoin Computer通过保留成员变量_amount
,可以对合约输出中的比特币数进行控制,结合_owners
变量,可以完成对比特币的转账。
下一篇我们将介绍Bitcoin Computer的token方案。