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

Web3 1.0 instances seem to share state (provider overwritten) #1188

Closed
benjamincburns opened this issue Nov 21, 2017 · 9 comments
Closed

Web3 1.0 instances seem to share state (provider overwritten) #1188

benjamincburns opened this issue Nov 21, 2017 · 9 comments

Comments

@benjamincburns
Copy link
Contributor

benjamincburns commented Nov 21, 2017

Observed this issue on 1.0-beta.26 - haven't tested other versions.

When I create an instance of web3, use it for a bit, then create a second instance with a different provider, the first instance's provider is overwritten.

I've modified test/setProvider.js to demonstrate the issue. These changes are given below as a diff taken against c4c92c3.

diff --git a/test/setProvider.js b/test/setProvider.js
index d0f4caf..52a3a15 100644
--- a/test/setProvider.js
+++ b/test/setProvider.js
@@ -54,7 +54,11 @@ describe('lib/web3/setProvider', function () {
         provider1.bzz = 'http://localhost:8500';
         provider2.bzz = 'http://swarm-gateways.net';
 
+        var provider3 = new FakeHttpProvider();
+        provider3.bzz = 'http://localhost2:8500';
+
         var lib = new Web3(provider1);
+        var lib2 = new Web3(provider3);
 
         assert.equal(lib.eth.currentProvider.constructor.name, provider1.constructor.name);
         assert.equal(lib.eth.net.currentProvider.constructor.name, provider1.constructor.name);
@@ -71,6 +75,21 @@ describe('lib/web3/setProvider', function () {
         assert.equal(lib.eth.accounts._requestManager.provider.constructor.name, provider1.constructor.name);
         assert.equal(lib.shh._requestManager.provider.constructor.name, provider1.constructor.name);
 
+        assert.equal(lib2.eth.currentProvider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.net.currentProvider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.personal.currentProvider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.Contract.currentProvider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.accounts.currentProvider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.shh.currentProvider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.bzz.currentProvider, provider3.bzz);
+
+        assert.equal(lib2.eth._requestManager.provider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.net._requestManager.provider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.personal._requestManager.provider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.Contract._requestManager.provider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.accounts._requestManager.provider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.shh._requestManager.provider.constructor.name, provider3.constructor.name);
+
 
         lib.setProvider(provider2);
 
@@ -89,6 +108,21 @@ describe('lib/web3/setProvider', function () {
         assert.equal(lib.eth.accounts._requestManager.provider.constructor.name, provider2.constructor.name);
         assert.equal(lib.shh._requestManager.provider.constructor.name, provider2.constructor.name);
 
+        assert.equal(lib2.eth.currentProvider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.net.currentProvider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.personal.currentProvider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.Contract.currentProvider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.accounts.currentProvider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.shh.currentProvider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.bzz.currentProvider, provider3.bzz);
+
+        assert.equal(lib2.eth._requestManager.provider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.net._requestManager.provider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.personal._requestManager.provider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.Contract._requestManager.provider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.eth.accounts._requestManager.provider.constructor.name, provider3.constructor.name);
+        assert.equal(lib2.shh._requestManager.provider.constructor.name, provider3.constructor.name);
+
 
     });
 
@benjamincburns
Copy link
Contributor Author

Note that this issue is blocking The addition of websockets and IPC to Ganache and ganache-cli (formerly TestRPC).

@benjamincburns
Copy link
Contributor Author

benjamincburns commented Nov 21, 2017

1 failing

  1) lib/web3/setProvider
       Web3 submodules should set the provider using constructor:

      AssertionError: expected 'IpcProvider' to equal 'HttpProvider'
      + expected - actual

      -IpcProvider
      +HttpProvider

      at Context.<anonymous> (test/setProvider.js:114:16)

Looks like it's failing on assert.equal(lib2.eth.Contract.currentProvider.constructor.name, provider3.constructor.name); after the 2nd call to lib.setProvider - I suppose I'll have a look there.

@benjamincburns
Copy link
Contributor Author

Contract.setProvider = function(provider, accounts) {
    // Contract.currentProvider = provider;
    core.packageInit(Contract, [provider]);

    Contract._ethAccounts = accounts;
};

The signature of core.packageInit is function (pkg, args) - in packageInit the current provider is tracked as pkg._provider. This apparently causes initialization of a second instance of Web3 to overwrite the first instance's .eth.Contract._provider.

@benjamincburns
Copy link
Contributor Author

From what I can tell, I think the design is over-constrained. It seems that you want to be able to do something like:

var web3 = new Web3();
web3.setProvider(...);
// compilation steps and/or fetching of ABI go here
var myContract = new web3.eth.Contract(...);

And I'd assume that adding myContract.setProvider(web3.currentProvider); or passing web3.currentProvider to the Contract constructor would be considered unacceptable boilerplate.

I had some fun with util.inherit and a bit of monkey patching to essentially give each instance of web3.eth its own Contract type, but that introduces some other chicken/egg issues which I'm having difficulty sorting out. I'll keep the patch around if anybody wants to collaborate on it, otherwise I think I've unblocked myself by just reimporting web3 in my test suite so that each entire object/type tree is disconnected. It's more than a bit atom bomb vs anthill, however...

@benjamincburns
Copy link
Contributor Author

I think I've unblocked myself by just reimporting web3 in my test suite so that each entire object/type tree is disconnected.

Yeah, that's not a reliable fix. For some reason it makes the tests pass on this computer, but imported modules are supposed to be cached. The fact that my tests pass makes me feel like I'm relying upon version-specific or undefined behaviour, and I'd rather not rely on it -- so this still blocks me.

@benjamincburns
Copy link
Contributor Author

@frozeman I asked around and was told that you'd be the person to ping about this issue. I'm happy to submit a PR w/ the fix, but I don't want to guess too much at what strategy you'd prefer I take. Feel free to ping me on gitter or the Consensys slack if you'd like to discuss. Happy to set up a face-to-face via Zoom as well.

@frozeman
Copy link
Contributor

Shared state was not planned, and I had quite some pains make the contract object inherit the provider. If you can. One up with a fix I’m happy to hear. You can contact me in Gitter and we can have a skype chat on Thursday

benjamincburns added a commit to benjamincburns/web3.js that referenced this issue Nov 22, 2017
@benjamincburns
Copy link
Contributor Author

@frozeman turns out I wasn't jumping through the right hoops last night and I managed to crack it. See #1191.

frozeman pushed a commit that referenced this issue Dec 21, 2017
* Fixes #1188

* Exercise standalone Contracts, plus extra set provider tests

* forgot to fix up new test during merge

* fix broken test

* Review changes: get rid of util.inherits, rename ContractWrapper to Contract
@raghwendra3
Copy link

  1. Inbox
    has a default message:
    TypeError: inbox.methods.message is not a function
    at Context.it (test/Inbox.test.js:23:38)

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! inbox@1.0.0 test: mocha
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the inbox@1.0.0 test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! /home/raghwendra/.npm/_logs/2018-03-10T21_14_29_204Z-debug.log

nachomazzara pushed a commit to nachomazzara/web3.js that referenced this issue Jun 4, 2020
* Fixes web3#1188

* Exercise standalone Contracts, plus extra set provider tests

* forgot to fix up new test during merge

* fix broken test

* Review changes: get rid of util.inherits, rename ContractWrapper to Contract
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants