Skip to content

Commit

Permalink
Merge pull request #3259 from ethereum/enhancement/add-receipt-to-errors
Browse files Browse the repository at this point in the history
Receipt added to transaction errors
  • Loading branch information
nivida committed Dec 9, 2019
2 parents b35e418 + 0ff7669 commit 8804708
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ Released with 1.0.0-beta.37 code base.
- ``BN`` and ``BigNumber`` objects are now supported by the ``abi.encodeParameter(s)`` method (#3238)
- ``getPendingTransactions`` added to web3-eth package (#3239)
- Revert instruction handling added which can get activated with the ``handleRevert`` module property (#3248)
- The ``receipt`` does now exist as property on the error object for transaction related errors (#3259)

### Changed

Expand Down
19 changes: 19 additions & 0 deletions packages/web3-core-helpers/src/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,26 @@ module.exports = {
var error = new Error('Transaction has been reverted by the EVM:\n' + JSON.stringify(receipt, null, 2));
error.reason = reason;
error.signature = signature;
error.receipt = receipt;

return error;
},
TransactionError: function(message, receipt) {
var error = new Error(message);
error.receipt = receipt;

return error;
},
NoContractAddressFoundError: function(receipt) {
return this.TransactionError('The transaction receipt didn\'t contain a contract address.', receipt);
},
ContractCodeNotStoredError: function(receipt) {
return this.TransactionError('The contract code couldn\'t be stored, please check your gas limit.', receipt);
},
TransactionRevertedWithoutReasonError: function(receipt) {
return this.TransactionError('Transaction has been reverted by the EVM:\n' + JSON.stringify(receipt, null, 2), receipt);
},
TransactionOutOfGasError: function(receipt) {
return this.TransactionError('Transaction ran out of gas. Please provide more gas:\n' + JSON.stringify(receipt, null, 2), receipt);
}
};
9 changes: 9 additions & 0 deletions packages/web3-core-helpers/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ export class errors {
static ConnectionTimeout(ms: string): Error;
static RevertInstructionError(reason: string, signature: string): RevertInstructionError
static TransactionRevertInstructionError(reason: string, signature: string, receipt: object): TransactionRevertInstructionError
static TransactionError(message: string, receipt: object): TransactionError
static NoContractAddressFoundError(receipt: object): TransactionError
static ContractCodeNotStoredError(receipt: object): TransactionError
static TransactionRevertedWithoutReasonError(receipt: object): TransactionError
static TransactionOutOfGasError(receipt: object): TransactionError
}

export class WebsocketProviderBase {
Expand Down Expand Up @@ -194,3 +199,7 @@ export interface TransactionRevertInstructionError extends Error {
reason: string;
signature: string;
}

export interface TransactionError extends Error {
receipt: object;
}
12 changes: 6 additions & 6 deletions packages/web3-core-method/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ Method.prototype._confirmTransaction = function (defer, result, payload) {
}

utils._fireError(
new Error('The transaction receipt didn\'t contain a contract address.'),
errors.NoContractAddressFoundError(receipt),
defer.eventEmitter,
defer.reject,
null,
Expand Down Expand Up @@ -375,7 +375,7 @@ Method.prototype._confirmTransaction = function (defer, result, payload) {

} else {
utils._fireError(
new Error('The contract code couldn\'t be stored, please check your gas limit.'),
errors.ContractCodeNotStoredError(receipt),
defer.eventEmitter,
defer.reject,
null,
Expand Down Expand Up @@ -437,7 +437,7 @@ Method.prototype._confirmTransaction = function (defer, result, payload) {
} catch (error) {
// Throw an normal revert error if no revert reason is given or the detection of it is disabled
utils._fireError(
new Error('Transaction has been reverted by the EVM:\n' + receiptJSON),
errors.TransactionRevertedWithoutReasonError(receipt),
defer.eventEmitter,
defer.reject,
null,
Expand All @@ -447,7 +447,7 @@ Method.prototype._confirmTransaction = function (defer, result, payload) {
} else {
// Throw OOG if status is not existing and provided gas and used gas are equal
utils._fireError(
new Error('Transaction ran out of gas. Please provide more gas:\n' + receiptJSON),
errors.TransactionOutOfGasError(receipt),
defer.eventEmitter,
defer.reject,
null,
Expand All @@ -474,7 +474,7 @@ Method.prototype._confirmTransaction = function (defer, result, payload) {
sub.unsubscribe();
promiseResolved = true;
utils._fireError(
new Error('Transaction was not mined within ' + method.transactionPollingTimeout + ' seconds, please make sure your transaction was properly sent. Be aware that it might still be mined!'),
errors.TransactionError('Transaction was not mined within ' + method.transactionPollingTimeout + ' seconds, please make sure your transaction was properly sent. Be aware that it might still be mined!'),
defer.eventEmitter,
defer.reject
);
Expand All @@ -484,7 +484,7 @@ Method.prototype._confirmTransaction = function (defer, result, payload) {
sub.unsubscribe();
promiseResolved = true;
utils._fireError(
new Error('Transaction was not mined within ' + method.transactionBlockTimeout + ' blocks, please make sure your transaction was properly sent. Be aware that it might still be mined!'),
errors.TransactionError('Transaction was not mined within ' + method.transactionBlockTimeout + ' blocks, please make sure your transaction was properly sent. Be aware that it might still be mined!'),
defer.eventEmitter,
defer.reject
);
Expand Down
122 changes: 122 additions & 0 deletions test/eth.sendTransaction.revert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
var assert = require('chai').assert;
var FakeHttpProvider = require('./helpers/FakeHttpProvider');
var Web3 = require('../packages/web3');

describe('sendTransaction revert:', function () {
var provider;
var web3;

beforeEach(function () {
provider = new FakeHttpProvider();
web3 = new Web3(provider);
web3.eth.handleRevert = true;
});

it('Errors without revert reason string', function (done) {
provider.injectResult('0x1234567');
provider.injectValidation(function (payload) {
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'eth_sendTransaction');
assert.deepEqual(
payload.params,
[{
from: "0xdbdbdb2cbd23b783741e8d7fcf51e459b497e4a6",
to: "0xdbdbdb2cbd23b783741e8d7fcf51e459b497e4a6",
value: "0x11f71f76bb1",
gasPrice: "0x4b7dddc97a"
}]
);
});

provider.injectResult(null);
provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_getTransactionReceipt');
});


// inject receipt
provider.injectResult({
"blockHash": "0x6fd9e2a26ab",
"blockNumber": "0x15df",
"transactionHash": "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
"transactionIndex": "0x1",
"contractAddress": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
"cumulativeGasUsed": "0x7f110",
"gasUsed": "0x7f110",
"status": "0x0"
});

var options = {
from: '0xdbdbdB2cBD23b783741e8d7fcF51e459b497e4a6',
to: '0xdbdbdB2cBD23b783741e8d7fcF51e459b497e4a6',
value: '1234567654321',
gasPrice: '324234234234'
};

web3.eth.sendTransaction(options).catch(function (error) {
assert.equal(error.receipt.status, false);
assert.equal(error.reason, undefined);
assert.equal(error.signature, undefined);

done();
});
});

it('Errors with revert reason string', function (done) {
provider.injectResult('0x1234567');
provider.injectValidation(function (payload) {
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'eth_sendTransaction');
assert.deepEqual(
payload.params,
[{
from: "0xdbdbdb2cbd23b783741e8d7fcf51e459b497e4a6",
to: "0xdbdbdb2cbd23b783741e8d7fcf51e459b497e4a6",
value: "0x11f71f76bb1",
gasPrice: "0x4b7dddc97a"
}]
);
});

provider.injectResult(null);
provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_getTransactionReceipt');
});


// inject receipt
provider.injectResult({
"blockHash": "0x6fd9e2a26ab",
"blockNumber": "0x15df",
"transactionHash": "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
"transactionIndex": "0x1",
"contractAddress": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
"cumulativeGasUsed": "0x7f110",
"gasUsed": "0x7f110",
"status": "0x0"
});
provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_getTransactionReceipt');
});

provider.injectResult('0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001a4e6f7420656e6f7567682045746865722070726f76696465642e000000000000');
provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_call');
});

var options = {
from: '0xdbdbdB2cBD23b783741e8d7fcF51e459b497e4a6',
to: '0xdbdbdB2cBD23b783741e8d7fcF51e459b497e4a6',
value: '1234567654321',
gasPrice: '324234234234'
};

web3.eth.sendTransaction(options).catch(function (error) {
assert.equal(error.receipt.status, false);
assert.equal(error.reason, 'Not enough Ether provided.');
assert.equal(error.signature, 'Error(String)');

done();
});
});
});

0 comments on commit 8804708

Please sign in to comment.