Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not getting success callback/ receipt with walletconnect with web3.js 1.3.3 - Closes #3891 #4304

Merged
merged 12 commits into from
Sep 22, 2021
Merged
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ Released with 1.0.0-beta.37 code base.
### Fixed

- Unable to send legacy transaction if network supported EIP-1559 (#4277)
- Fixed bug in sending transaction with providers not support "newBlockHeaders" event (#3891)

### Changed

Expand All @@ -447,4 +448,5 @@ Released with 1.0.0-beta.37 code base.
- lerna from 3.22.1 to 4.0.0 (#4231)
- Dropped build tests in CI for Node v8 and v10, and added support for Node v14
- Change default value for `maxPriorityFeePerGas` from `1 Gwei` to `2.5 Gwei` (#4284)
- Fixed bug in signTransaction (#4295)
- Fixed bug in signTransaction (#4295)
- Introduced new configuration "blockHeaderTimeout" for waiting of block headers for transaction receipt (#3891)
21 changes: 21 additions & 0 deletions docs/web3-eth-contract.rst
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,27 @@ Returns

------------------------------------------------------------------------------

.. _eth-contract-blockHeaderTimeout:

blockHeaderTimeout
=====================

.. code-block:: javascript

web3.eth.Contract.blockHeaderTimeout
contract.blockHeaderTimeout // on contract instance

The ``blockHeaderTimeout`` is used over socket-based connections. This option defines the amount seconds it should wait for "newBlockHeaders" event before falling back to polling to fetch transaction receipt.


-------
Returns
-------

``number``: The current value of blockHeaderTimeout (default: 5 seconds)

------------------------------------------------------------------------------

.. _eth-contract-module-transactionconfirmationblocks:

transactionConfirmationBlocks
Expand Down
34 changes: 34 additions & 0 deletions docs/web3-eth.rst
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,40 @@ Example
web3.eth.transactionBlockTimeout = 100;


------------------------------------------------------------------------------

.. _eth-contract-blockHeaderTimeout:

blockHeaderTimeout
=====================

.. code-block:: javascript

web3.eth.Contract.blockHeaderTimeout
contract.blockHeaderTimeout // on contract instance

The ``blockHeaderTimeout`` is used over socket-based connections. This option defines the amount seconds it should wait for "newBlockHeaders" event before falling back to polling to fetch transaction receipt.


-------
Returns
-------

``number``: The current value of blockHeaderTimeout (default: 5 seconds)

-------
Example
-------

.. code-block:: javascript

web3.eth.blockHeaderTimeout;
> 5

// set the transaction confirmations blocks
web3.eth.blockHeaderTimeout = 10;


------------------------------------------------------------------------------

.. _web3-module-transactionconfirmationblocks:
Expand Down
36 changes: 25 additions & 11 deletions packages/web3-core-method/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ var Method = function Method(options) {
this.transactionBlockTimeout = options.transactionBlockTimeout || 50;
this.transactionConfirmationBlocks = options.transactionConfirmationBlocks || 24;
this.transactionPollingTimeout = options.transactionPollingTimeout || 750;
this.blockHeaderTimeout = options.blockHeaderTimeout || 5; // 5 seconds
nazarhussain marked this conversation as resolved.
Show resolved Hide resolved
this.defaultCommon = options.defaultCommon;
this.defaultChain = options.defaultChain;
this.defaultHardfork = options.defaultHardfork;
Expand Down Expand Up @@ -547,22 +548,35 @@ Method.prototype._confirmTransaction = function (defer, result, payload) {

// start watching for confirmation depending on the support features of the provider
var startWatching = function (existingReceipt) {
let blockHeaderArrived = false;

const startInterval = () => {
intervalId = setInterval(checkConfirmation.bind(null, existingReceipt, true), 1000);
};

if (!this.requestManager.provider.on) {
startInterval();
} else {
_ethereumCall.subscribe('newBlockHeaders', function (err, blockHeader, sub) {
if (err || !blockHeader) {
// fall back to polling
startInterval();
} else {
checkConfirmation(existingReceipt, false, err, blockHeader, sub);
}
});
// If provider do not support event subscription use polling
if(!this.requestManager.provider.on) {
jdevcs marked this conversation as resolved.
Show resolved Hide resolved
return startInterval();
}

// Subscribe to new block headers to look for tx receipt
_ethereumCall.subscribe('newBlockHeaders', function (err, blockHeader, sub) {
blockHeaderArrived = true;

if (err || !blockHeader) {
spacesailor24 marked this conversation as resolved.
Show resolved Hide resolved
// fall back to polling
return startInterval();
}

checkConfirmation(existingReceipt, false, err, blockHeader, sub);
});

// Fallback to polling if tx receipt didn't arrived in "blockHeaderTimeout" [10 seconds]
setTimeout(() => {
if(!blockHeaderArrived) {
startInterval();
}
}, this.blockHeaderTimeout * 1000);
}.bind(this);


Expand Down
13 changes: 13 additions & 0 deletions packages/web3-eth-contract/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,19 @@ var Contract = function Contract(jsonInterface, address, options) {
},
enumerable: true
});
Object.defineProperty(this, 'blockHeaderTimeout', {
get: function () {
if (_this.options.blockHeaderTimeout === 0) {
return _this.options.blockHeaderTimeout;
}

return _this.options.blockHeaderTimeout || this.constructor.blockHeaderTimeout;
},
set: function (val) {
_this.options.blockHeaderTimeout = val;
},
enumerable: true
});
Object.defineProperty(this, 'defaultAccount', {
get: function () {
return defaultAccount;
Expand Down
19 changes: 19 additions & 0 deletions packages/web3-eth/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ var Eth = function Eth() {
var transactionBlockTimeout = 50;
var transactionConfirmationBlocks = 24;
var transactionPollingTimeout = 750;
var blockHeaderTimeout = 5;
nazarhussain marked this conversation as resolved.
Show resolved Hide resolved
var maxListenersWarningThreshold = 100;
var defaultChain, defaultHardfork, defaultCommon;

Expand Down Expand Up @@ -222,6 +223,23 @@ var Eth = function Eth() {
},
enumerable: true
});
Object.defineProperty(this, 'blockHeaderTimeout', {
get: function () {
return blockHeaderTimeout;
},
set: function (val) {
blockHeaderTimeout = val;

// also set on the Contract object
_this.Contract.blockHeaderTimeout = blockHeaderTimeout;

// update defaultBlock
methods.forEach(function(method) {
method.blockHeaderTimeout = blockHeaderTimeout;
});
},
enumerable: true
});
Object.defineProperty(this, 'defaultAccount', {
get: function () {
return defaultAccount;
Expand Down Expand Up @@ -333,6 +351,7 @@ var Eth = function Eth() {
this.Contract.transactionBlockTimeout = this.transactionBlockTimeout;
this.Contract.transactionConfirmationBlocks = this.transactionConfirmationBlocks;
this.Contract.transactionPollingTimeout = this.transactionPollingTimeout;
this.Contract.blockHeaderTimeout = this.blockHeaderTimeout;
this.Contract.handleRevert = this.handleRevert;
this.Contract._requestManager = this._requestManager;
this.Contract._ethAccounts = this.accounts;
Expand Down
25 changes: 25 additions & 0 deletions test/eth.blockHeaderTimeout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
var chai = require('chai');
var assert = chai.assert;
var Eth = require('../packages/web3-eth');

var eth = new Eth();

var setValue = 123;

describe('web3.eth', function () {
describe('blockHeaderTimeout', function () {
it('should check if blockHeaderTimeout is set to proper value', function () {
assert.equal(eth.blockHeaderTimeout, 5);
assert.equal(eth.Contract.blockHeaderTimeout, 5);
assert.equal(eth.getCode.method.blockHeaderTimeout, 5);
});
it('should set blockHeaderTimeout for all sub packages is set to proper value, if Eth package is changed', function () {
eth.blockHeaderTimeout = setValue;

assert.equal(eth.blockHeaderTimeout, setValue);
assert.equal(eth.Contract.blockHeaderTimeout, setValue);
assert.equal(eth.getCode.method.blockHeaderTimeout, setValue);
});
});
});

61 changes: 61 additions & 0 deletions test/method.buildCall.js
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,67 @@ describe('lib/web3/method', function () {
gasPrice: '23435234234'
})
});

it('should fallback to polling if provider support `on` but `newBlockHeaders` does not arrive in `blockHeaderTimeout` seconds', function (done) {
spacesailor24 marked this conversation as resolved.
Show resolved Hide resolved
const provider = new FakeHttpProvider();
// provider with method 'on' but no subscription capabilities should use polling
provider.on = (...args) => {}
const eth = new Eth(provider);

const method = new Method({
name: 'sendTransaction',
call: 'eth_sendTransaction',
params: 1,
inputFormatter: [formatters.inputTransactionFormatter]
});
method.setRequestManager(eth._requestManager, eth);
method.blockHeaderTimeout = 1;

// generate send function
const send = method.buildCall();

// add results
provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_sendTransaction');
assert.deepEqual(payload.params, [{
from: '0x11f4d0a3c12e86b4b5f39b213f7e19d048276dae',
to: '0x11f4d0a3c12e86b4b5f39b213f7e19d048276dae',
value: '0xa',
gasPrice: "0x574d94bba"
}]);
});
provider.injectResult('0x1234567453543456321456321'); // tx hash

provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_getTransactionReceipt');
assert.deepEqual(payload.params, ['0x1234567453543456321456321']);
});
provider.injectResult(null);

provider.injectValidation(function (payload) {
// here is the check.
// first will try subscribing with `eth_subscribe`.
assert.equal(payload.method, 'eth_subscribe');
assert.deepEqual(payload.params, ['newHeads']);
});
provider.injectResult(null);

// after failing with `eth_subscribe`,
// it should start polling with `eth_getTransactionReceipt`
provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_getTransactionReceipt');
assert.deepEqual(payload.params, ['0x1234567453543456321456321']);
done();
});
provider.injectResult(null);

send({
from: '0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe',
to: '0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe',
value: '0xa',
gasPrice: '23435234234'
})
});
});
});