网上和书上的教程大多是在私有链单机CPU挖矿的情况,遗漏了实战环境中遇到的问题。接下来一步步的阐述实战经验,并结合理论分析。
有些概念先介绍下
transactionHash:交易的流水号,转账和执行合约方法都是交易。
blockHash:根据区块内容计算的唯一哈希值
blockNumber:区块号,按数字加1累加。
分叉的情况,多块区块使用同个blockNumber,但不同blockHash。
矿机状态图
先看初学者的一段代码:
合约代码:
contract Calucator {
function Calucator() public
{
}
function addNumber(uint a,uint b) public returns(uint k)
{
k= a+b;
returnk;
}
}
Js代码:
App.contracts.Calucator.deployed().then(function(instance) {
return instance.addNumber(1,2);
}).then(function(result) {
console.log("result:"+result);
});
预期控制台显示的结果是3,但是result的结果是:
result = {tx:"0x69ddf34a618cd621144fb26dd3e479a85c9ec0bb6c5e2ac76b6aefe9aa74bad5",receipt: {…}, logs: Array(0)}调用合约的方法,返回的是交易hash,合约代码的返回值需要通过回调事件返回。
修改后的代码如下: 合约代码:
contract Calucator {
event returnValue(
address indexed _from,
uint indexed _value
);
function Calucator() public {
}
function addNumber(uint a,uint b) public
{
uint k = a+b;
emit returnValue(msg.sender, k);
}
}
Js代码:
eventCallBack:function(error, result){
if(!error)
console.log(result);
},
markAdopted: function() {
var event;
App.contracts.Calucator.deployed().then(function(instance){
event= instance.returnValue();
web3.personal.unlockAccount(web3.eth.accounts[0],'123456',999);
event.watch(App.eventCallBack);
return instance.addNumber(1,2);
}).then(function(result){
console.log("result:"+result);
});
}
如果搭建的是私有链环境,挖矿速度通常设置比较快,很快就可以捕获到事件的返回,但是在以太坊公有链上,需要等待十几秒的时间,打包区块时才执行合约代码触发回调事件。
然而,网上教程没有告诉你的是:事件回调后得到的区块hash并不是最终保存交易记录的区块的blockHash.原因是由于两个或者多个矿工几乎同时发现了一个区块引起的分叉。
在某个时刻网络上的矿机同时挖出两个区块,blockNumber都为N+1,但是blockHash不一样,两个区块都会执行合约的代码,触发两次回调。一个区块是否最终得到确认保存在主链上需要等六个区块的确认,第N+7的区块生成时,才能最终确认哪个N+1的块是永久保存在主链上。