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

Bound lookup in arrays with duplicate #4842

Merged
merged 13 commits into from
Jan 29, 2024
Prev Previous commit
Next Next commit
Merge branch 'master' into feature/array-bound-with-duplicates
  • Loading branch information
Amxx committed Jan 18, 2024
commit c4726c8a2b7eaa3c85d4779aafe81a00edd0c9db
52 changes: 21 additions & 31 deletions test/utils/Arrays.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');

const { randomArray, generators } = require('../helpers/random');

// See https://en.cppreference.com/w/cpp/algorithm/ranges/lower_bound
const lowerBound = (array, value) => {
const i = array.findIndex(element => value <= element);
Expand Down Expand Up @@ -102,42 +104,30 @@ describe('Arrays', function () {
}
});

describe('unsafeAccess', function () {
for (const [name, { artifact, generator }] of Object.entries({
address: {
artifact: 'AddressArraysMock',
generator: () => ethers.getAddress(ethers.hexlify(ethers.randomBytes(20))),
},
bytes32: {
artifact: 'Bytes32ArraysMock',
generator: () => ethers.hexlify(ethers.randomBytes(32)),
},
uint256: {
artifact: 'Uint256ArraysMock',
generator: () => ethers.toBigInt(ethers.randomBytes(32)),
},
describe.only('unsafeAccess', function () {
for (const [title, { artifact, elements }] of Object.entries({
address: { artifact: 'AddressArraysMock', elements: randomArray(generators.address, 10) },
bytes32: { artifact: 'Bytes32ArraysMock', elements: randomArray(generators.bytes32, 10) },
uint256: { artifact: 'Uint256ArraysMock', elements: randomArray(generators.uint256, 10) },
})) {
it(name, async function () {
const elements = Array(10).fill().map(generator);
const contract = await ethers.deployContract(artifact, [elements]);

const fixture = async () => {
const contracts = {};
for (const [name, { artifact, elements }] of Object.entries(contractCases)) {
contracts[name] = await ethers.deployContract(artifact, [elements]);
}
return { contracts };
};
describe(title, function () {
const fixture = async () => {
return { mock: await ethers.deployContract(artifact, [elements]) };
};

beforeEach(async function () {
Object.assign(this, await loadFixture(fixture));
});
beforeEach(async function () {
Object.assign(this, await loadFixture(fixture));
});

for (const [name, { elements }] of Object.entries(contractCases)) {
it(name, async function () {
for (const i in elements) {
expect(await contract.unsafeAccess(i)).to.be.equal(elements[i]);
it(`unsafeAccess within bounds #${i}`, async function () {
expect(await this.mock.unsafeAccess(i)).to.equal(elements[i]);
});
}

it('unsafeAccess outside bounds', async function () {
await expect(this.mock.unsafeAccess(elements.length)).to.not.be.rejected;
});
});
}
});
Expand Down
35 changes: 35 additions & 0 deletions test/utils/structs/Checkpoints.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');

const { VALUE_SIZES } = require('../../../scripts/generate/templates/Checkpoints.opts');

<<<<<<< HEAD
const $Checkpoints = artifacts.require('$Checkpoints');

// The library name may be 'Checkpoints' or 'CheckpointsUpgradeable'
Expand All @@ -14,6 +15,11 @@ contract('Checkpoints', function () {
this.mock = await $Checkpoints.new();
});

=======
const last = array => (array.length ? array[array.length - 1] : undefined);

describe('Checkpoints', function () {
>>>>>>> master
for (const length of VALUE_SIZES) {
describe(`Trace${length}`, function () {
const fixture = async () => {
Expand Down Expand Up @@ -86,6 +92,7 @@ contract('Checkpoints', function () {
});

it('returns latest value', async function () {
<<<<<<< HEAD
expect(await this.methods.latest()).to.be.bignumber.equal(this.checkpoints.at(-1).value);

const ckpt = await this.methods.latestCheckpoint();
Expand All @@ -97,6 +104,16 @@ contract('Checkpoints', function () {
it('cannot push values in the past', async function () {
await expectRevertCustomError(
this.methods.push(this.checkpoints.at(-1).key - 1, '0'),
=======
const latest = this.checkpoints.at(-1);
expect(await this.methods.latest()).to.equal(latest.value);
expect(await this.methods.latestCheckpoint()).to.have.ordered.members([true, latest.key, latest.value]);
});

it('cannot push values in the past', async function () {
await expect(this.methods.push(this.checkpoints.at(-1).key - 1n, 0n)).to.be.revertedWithCustomError(
this.mock,
>>>>>>> master
'CheckpointUnorderedInsertion',
);
});
Expand All @@ -109,23 +126,35 @@ contract('Checkpoints', function () {

// update last key
await this.methods.push(this.checkpoints.at(-1).key, newValue);
<<<<<<< HEAD
expect(await this.methods.latest()).to.be.bignumber.equal(newValue);
=======
expect(await this.methods.latest()).to.equal(newValue);
>>>>>>> master

// check that length did not change
expect(await this.methods.length()).to.equal(this.checkpoints.length);
});

it('lower lookup', async function () {
for (let i = 0; i < 14; ++i) {
<<<<<<< HEAD
const value = this.checkpoints.find(x => i <= x.key)?.value || '0';
=======
const value = this.checkpoints.find(x => i <= x.key)?.value || 0n;
>>>>>>> master

expect(await this.methods.lowerLookup(i)).to.equal(value);
}
});

it('upper lookup & upperLookupRecent', async function () {
for (let i = 0; i < 14; ++i) {
<<<<<<< HEAD
const value = this.checkpoints.findLast(x => i >= x.key)?.value || '0';
=======
const value = last(this.checkpoints.filter(x => i >= x.key))?.value || 0n;
>>>>>>> master

expect(await this.methods.upperLookup(i)).to.equal(value);
expect(await this.methods.upperLookupRecent(i)).to.equal(value);
Expand All @@ -147,9 +176,15 @@ contract('Checkpoints', function () {
}

for (let i = 0; i < 25; ++i) {
<<<<<<< HEAD
const value = allCheckpoints.findLast(x => i >= x.key)?.value || '0';
expect(await this.methods.upperLookup(i)).to.be.bignumber.equal(value);
expect(await this.methods.upperLookupRecent(i)).to.be.bignumber.equal(value);
=======
const value = last(allCheckpoints.filter(x => i >= x.key))?.value || 0n;
expect(await this.methods.upperLookup(i)).to.equal(value);
expect(await this.methods.upperLookupRecent(i)).to.equal(value);
>>>>>>> master
}
});
});
Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.