Poll chain state for contract callback invocation

Previously we relied on filters to watch for block events for firing contract-
creation callback functions. With this change, we now poll the chain's state on
the javascript side using `setInterval`.

This is necessary for low-latency consensus mechanisms like Raft, where a block
event reguarly fires before the web3 layer is able to set the filter to watch
for such events.

This fixes #86.
This commit is contained in:
Brian Schroeder 2017-04-06 13:30:59 -04:00
parent d442011414
commit 370b9024ec
1 changed files with 49 additions and 46 deletions

View File

@ -2897,27 +2897,37 @@ var addEventsToContract = function (contract) {
*/
var checkForContractAddress = function(contract, callback){
var count = 0,
callbackFired = false;
callbackFired = false,
filter = null,
interval = null,
stop = function() {
if (interval) { clearInterval(interval); };
if (filter) { filter.stopWatching(); };
callbackFired = true;
};
// wait for receipt
var filter = contract._eth.filter('latest', function(e){
// Track the number of blocks that are added to the chain so that we can
// timeout.
filter = contract._eth.filter('latest', function(e){
if (!e && !callbackFired) {
count++;
// stop watching after 50 blocks (timeout)
if (count > 50) {
filter.stopWatching();
callbackFired = true;
stop();
if (callback)
callback(new Error('Contract transaction couldn\'t be found after 50 blocks'));
else
throw new Error('Contract transaction couldn\'t be found after 50 blocks');
}
}
});
} else {
// If we want to guarantee the firing of our callback, using a filter
// alone won't suffice, because there is always the possibility that our
// block event already fired in high-throughput/non-proof-of-work
// scenarios:
interval = setInterval(function() {
contract._eth.getTransactionReceipt(contract.transactionHash, function(e, receipt){
if(receipt && !callbackFired) {
@ -2927,13 +2937,9 @@ var checkForContractAddress = function(contract, callback){
if(callbackFired || !code)
return;
filter.stopWatching();
callbackFired = true;
stop();
if(code.length > 2) {
// console.log('Contract code deployed!');
contract.address = receipt.contractAddress;
// attach events and methods again after we have
@ -2943,7 +2949,6 @@ var checkForContractAddress = function(contract, callback){
// call callback for the second time
if(callback)
callback(null, contract);
} else {
if(callback)
callback(new Error('The contract code couldn\'t be stored, please check your gas amount.'));
@ -2953,9 +2958,7 @@ var checkForContractAddress = function(contract, callback){
});
}
});
}
}
});
}, 250);
};
/**