openzeppelin-test-helpers icon indicating copy to clipboard operation
openzeppelin-test-helpers copied to clipboard

Potential error in expectEvent.contains

Open terenceyak opened this issue 5 years ago • 9 comments

For the expectEvent.contains function, if we look at the else-if condition

https://github.com/OpenZeppelin/openzeppelin-test-helpers/blob/ab4b86771431ce17592d5fb9f0a22ce913127517/src/expectEvent.js#L129-L134

This condition is executed if either args[key] or the value is a BN object.

However, the assertion on line 132 fails in the case args[key] is not a BN but of other types like a string, throwing an error like the following:

AssertionError: expected '3' to be an instance of BN

A potential fix would be to ensure args[key] is a BN before the assertion.

    if(!isBN(args[key])) {
      args[key] = new BN(args[key]);
    }

Sidenote:

I encountered this issue when I was using expectEvent.inTransaction for an event with BN arguments. I notice that decodeLogs in expectEvent uses web3.eth.abi.decodeLogs, which based on the docs returns a string for all variables even uint. This is shown below:

web3.eth.abi.decodeLog([{
    type: 'string',
    name: 'myString'
},{
    type: 'uint256',
    name: 'myNumber',
    indexed: true
},{
    type: 'uint8',
    name: 'mySmallNumber',
    indexed: true
}],
'0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000748656c6c6f252100000000000000000000000000000000000000000000000000',
['0x000000000000000000000000000000000000000000000000000000000000f310', '0x0000000000000000000000000000000000000000000000000000000000000010']);
> Result {
    '0': 'Hello%!',
    '1': '62224',
    '2': '16',
    myString: 'Hello%!',
    myNumber: '62224',
    mySmallNumber: '16'
}

terenceyak avatar Apr 07 '20 02:04 terenceyak

Hi @terenceyak! Unfortunately, I wasn’t able to reproduce this issue. I tried the following:

I created a contract MyContract and used expectEvent in the test with the event as you described. Apologies if I am missing something.

MyContract.sol

pragma solidity ^0.5.0;

contract MyContract {
    
    event MyEvent(string myString, uint256 indexed myNumber, uint8 mySmallNumber);
    
    function doStuff() public {
        emit MyEvent("Hello%!", 62224, 16);
    }
}

MyContract.test.js

const { accounts, contract } = require('@openzeppelin/test-environment');
const { expect } = require('chai');

// Import utilities from Test Helpers
const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');

const MyContract = contract.fromArtifact('MyContract');

describe('MyContract', function () {
  const [ owner, other ] = accounts;

  // Use large integers ('big numbers')
  const myNumberValue = new BN('62224');
  const mySmallNumberValue = new BN('16');

  beforeEach(async function () {
    this.contract = await MyContract.new({ from: owner });
  });

  it('contract emits an event', async function () {
    const receipt = await this.contract.doStuff({ from: owner });

    console.log(receipt.logs[0]);
    expectEvent(receipt, 'MyEvent', { myString: 'Hello%!', myNumber: myNumberValue, mySmallNumber: mySmallNumberValue });
    expectEvent(receipt, 'MyEvent', { 0: 'Hello%!', 1: myNumberValue, 2: mySmallNumberValue });
  });
});

Thanks so much for reporting it! The project owner will review and triage this issue during the next week.

abcoathup avatar Apr 07 '20 06:04 abcoathup

I think the bug would happen when one does: expectEvent(receipt, 'MyEvent', { myNumber: '62224' }). So when the argument is a string and not already converted to BN.

We want it to work with strings so we may be missing a conversion.

frangio avatar Apr 07 '20 18:04 frangio

Hi both,

I have debugged the issue further, and have narrowed the problem down to the following line.

https://github.com/OpenZeppelin/openzeppelin-test-helpers/blob/ab4b86771431ce17592d5fb9f0a22ce913127517/src/expectEvent.js#L132

With reference to the following example:

      expect('11').to.be.bignumber.equal(new BN(11));

The above line passes tests when the web3 is version 1.2.2 but gives the following error when web3 is version 1.2.6

     AssertionError: expected '11' to be an instance of BN

Let me know if you are not able to reproduce, i will create a repo just for this.

terenceyak avatar Apr 11 '20 08:04 terenceyak

That's very interesting, the recent BN releases shouldn't have altered that behavior. Could you share a simple snippet of your tests so we can reproduce the issue? Thanks!

nventuro avatar Apr 13 '20 17:04 nventuro

I added the test that I thought would catch this but it succeeds on my computer.

See https://github.com/frangio/openzeppelin-test-helpers/commit/671da752df8035e63e82109df60ed8558b27dc43.

frangio avatar Apr 13 '20 18:04 frangio

Hi all,

@nventuro is right, it is not web3 that caused the issue. I dug deeper, and found that the main issue is due to a different version of chai-bn on my repo. I was using v0.1.1 while the version used in this repo is v0.2.1.

I have reproduced the bug by replacing the chai-bn version used in the test helpers here.

It appears that there are more errors that pop up with the current test.

I also note that in setup.js, you guys have noted:

// The chai module used internally by us may not be the same one that the user
// has in their own tests. This can happen if the version ranges required don't
// intersect, or if the package manager doesn't dedupe the modules for any
// other reason. We do our best to install chai-bn for the user.

Not sure if you guys would like to enforce the use of the chai-bn version in this repo to prevent the above issue from happening. Otherwise, the repo has to be compatible with all other chai-bn versions as well.

terenceyak avatar Apr 15 '20 05:04 terenceyak

I'm pretty sure that comment is not related to this issue.

Even if you have installed [email protected] in your repo, test-helpers has its own dependency of [email protected], and expectEvent should be using that.

Can you provide a full repository of a project where we can reproduce the issue? It should be a project that installs test-helpers as a dependency, not a fork of test-helpers itself.

frangio avatar Apr 15 '20 18:04 frangio

Hi @frangio,

The bug is probably due to my own poor management of dependencies in my code. I have reproduced a passing and failing branch to showcase this explained below.

I found that using your own chai-bn after importing the test helpers would overwrite the chai-bn version in the helpers and use the local one instead. You can view the failing branch here.

Changing the import order and importing the test helpers after a local chai-bn import would lead to the test passing. You can view the passing branch here.

Hope it helps!

terenceyak avatar Apr 16 '20 13:04 terenceyak

I think this is a non-issue given the comment above, but could you share a bit on why you're installing and importing chai-bn yourself? It is meant to be an internal package that you don't need to know about.

nventuro avatar May 04 '20 19:05 nventuro