The home for Hyperlane core contracts, sdk packages, and other infrastructure
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
hyperlane-monorepo/solidity/core/test/validatorManager.test.ts

151 lines
4.4 KiB

import { ethers } from 'hardhat';
import { expect } from 'chai';
import { types, utils, Validator } from '@abacus-network/utils';
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import {
Outbox__factory,
Outbox,
ValidatorManager__factory,
ValidatorManager,
} from '../types';
const domainHashCases = require('../../../vectors/domainHash.json');
const localDomain = 1000;
describe('ValidatorManager', async () => {
let signer: SignerWithAddress,
fakeSigner: SignerWithAddress,
validatorManager: ValidatorManager,
validator: Validator,
fakeValidator: Validator;
before(async () => {
[signer, fakeSigner] = await ethers.getSigners();
validator = await Validator.fromSigner(signer, localDomain);
fakeValidator = await Validator.fromSigner(fakeSigner, localDomain);
});
beforeEach(async () => {
const validatorManagerFactory = new ValidatorManager__factory(signer);
validatorManager = await validatorManagerFactory.deploy();
await validatorManager.enrollValidator(localDomain, validator.address);
});
it('Accepts validator signature', async () => {
const root = ethers.utils.formatBytes32String('root');
const index = 1;
const { signature } = await validator.signCheckpoint(root, index);
const isValid = await validatorManager.isValidatorSignature(
localDomain,
root,
index,
signature,
);
expect(isValid).to.be.true;
});
it('Rejects non-validator signature', async () => {
const root = ethers.utils.formatBytes32String('root');
const index = 1;
const { signature } = await fakeValidator.signCheckpoint(root, index);
const isValid = await validatorManager.isValidatorSignature(
localDomain,
root,
index,
signature,
);
expect(isValid).to.be.false;
});
it('Calculated domain hash matches Rust-produced domain hash', async () => {
// Compare Rust output in json file to solidity output (json file matches
// hash for local domain of 1000)
for (let testCase of domainHashCases) {
const { expectedDomainHash } = testCase;
const domainHash = await validatorManager.domainHash(
testCase.outboxDomain,
);
expect(domainHash).to.equal(expectedDomainHash);
}
});
describe('improper checkpoints', async () => {
let outbox: Outbox;
beforeEach(async () => {
const outboxFactory = new Outbox__factory(signer);
outbox = await outboxFactory.deploy(localDomain);
await outbox.initialize(validatorManager.address);
});
it('Accepts improper checkpoint from validator', async () => {
const root = ethers.utils.formatBytes32String('root');
const index = 1;
const { signature } = await validator.signCheckpoint(root, index);
// Send message with signer address as msg.sender
await expect(
validatorManager.improperCheckpoint(
outbox.address,
root,
index,
signature,
),
)
.to.emit(validatorManager, 'ImproperCheckpoint')
.withArgs(
outbox.address,
localDomain,
validator.address,
root,
index,
signature,
);
expect(await outbox.state()).to.equal(types.AbacusState.FAILED);
});
it('Rejects improper checkpoint from non-validator', async () => {
const root = ethers.utils.formatBytes32String('root');
const index = 1;
const { signature } = await fakeValidator.signCheckpoint(root, index);
// Send message with signer address as msg.sender
await expect(
validatorManager.improperCheckpoint(
outbox.address,
root,
index,
signature,
),
).to.be.revertedWith('!validator sig');
});
it('Rejects proper checkpoint from validator', async () => {
const message = `0x${Buffer.alloc(10).toString('hex')}`;
await outbox.dispatch(
localDomain,
utils.addressToBytes32(signer.address),
message,
);
await outbox.checkpoint();
const [root, index] = await outbox.latestCheckpoint();
const { signature } = await validator.signCheckpoint(
root,
index.toNumber(),
);
// Send message with signer address as msg.sender
await expect(
validatorManager.improperCheckpoint(
outbox.address,
root,
index,
signature,
),
).to.be.revertedWith('!improper');
});
});
});