Skip to content

Commit

Permalink
Poll chain state for contract callback invocation
Browse files Browse the repository at this point in the history
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 ethereum#86.
  • Loading branch information
bts committed Apr 10, 2017
1 parent d442011 commit 370b902
Showing 1 changed file with 42 additions and 39 deletions.
81 changes: 42 additions & 39 deletions internal/jsre/ethereum_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -2897,65 +2897,68 @@ 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');
}
}
});
// 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) {
} else {
contract._eth.getTransactionReceipt(contract.transactionHash, function(e, receipt){
if(receipt && !callbackFired) {
contract._eth.getCode(receipt.contractAddress, function(e, code){
/*jshint maxcomplexity: 6 */
if(callbackFired || !code)
return;
filter.stopWatching();
callbackFired = true;
if(code.length > 2) {
contract._eth.getCode(receipt.contractAddress, function(e, code){
/*jshint maxcomplexity: 6 */
// console.log('Contract code deployed!');
if(callbackFired || !code)
return;
contract.address = receipt.contractAddress;
stop();
// attach events and methods again after we have
addFunctionsToContract(contract);
addEventsToContract(contract);
if(code.length > 2) {
contract.address = receipt.contractAddress;
// call callback for the second time
if(callback)
callback(null, contract);
// attach events and methods again after we have
addFunctionsToContract(contract);
addEventsToContract(contract);
} else {
if(callback)
callback(new Error('The contract code couldn\'t be stored, please check your gas amount.'));
else
throw new Error('The contract code couldn\'t be stored, please check your gas amount.');
}
});
// 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.'));
else
throw new Error('The contract code couldn\'t be stored, please check your gas amount.');
}
});
}
}
});
});
}, 250);
};
/**
Expand Down

0 comments on commit 370b902

Please sign in to comment.