Working with testrpc
hides you from one reality in particular when working with a blockchain. That is that sometimes the time to finish a transaction can take some time. The mining to fully realize the transaction not only has a cost in ether (for Ethereum) but a cost in time as you wait for your transaction to complete.
Moving your application to the testnet
will show you this right away. Now, when you have this happen you'll start to wonder how to handle something like an update to your screen after
the transaction is complete.
Here is a pattern that works using a function listed below that gets the promise of an Ethereum transaction when it is mined.
You call your sendTransaction
then pass your transaction hash into getTransactionRecipteMined
with a then
in which you have your function to update your UI.
For example:
console.log("calling initialize");
txHash = contractInstance.initialize.sendTransaction(paramA, paramB, paramC,
{from: account, gas: 3000000});
return web3.eth.getTransactionReceiptMined(txHash).then(function (receipt) {
console.log("receipt");
console.log(receipt);
populateUI(contractInstance);
});
How is getTransactionReceiptMined setup? I put the following at the top of my index.js file.
web3.eth.getTransactionReceiptMined= function getTransactionReceiptMined(txHash, interval) {
const self = this;
const transactionReceiptAsync = function(resolve, reject) {
self.getTransactionReceipt(txHash, (error, receipt) => {
if (error) {
reject(error);
} else if (receipt == null) {
setTimeout(
() => transactionReceiptAsync(resolve, reject),
interval ? interval : 500);
} else {
resolve(receipt);
}
});
};
if (Array.isArray(txHash)) {
return Promise.all(txHash.map(
oneTxHash => self.getTransactionReceiptMined(oneTxHash, interval)));
} else if (typeof txHash === "string") {
return new Promise(transactionReceiptAsync);
} else {
throw new Error("Invalid Type: " + txHash);
}
};