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/abacus-core/test/validatorManager.test.ts

150 lines
4.3 KiB

import { ethers, abacus } from 'hardhat';
import { expect } from 'chai';
import { AbacusState, Validator } from './lib/core';
import { Signer } from './lib/types';
import {
Home__factory,
Home,
ValidatorManager__factory,
ValidatorManager,
} from '../typechain';
const homeDomainHashCases = require('../../../vectors/homeDomainHash.json');
const localDomain = 1000;
describe('ValidatorManager', async () => {
let signer: Signer,
fakeSigner: Signer,
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.setValidator(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 homeDomainHashCases) {
const { expectedDomainHash } = testCase;
const domainHash = await validatorManager.domainHash(testCase.homeDomain);
expect(domainHash).to.equal(expectedDomainHash);
}
});
describe('improper checkpoints', async () => {
let home: Home;
beforeEach(async () => {
const homeFactory = new Home__factory(signer);
home = await homeFactory.deploy(localDomain);
await home.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(
home.address,
root,
index,
signature,
),
)
.to.emit(validatorManager, 'ImproperCheckpoint')
.withArgs(
home.address,
localDomain,
validator.address,
root,
index,
signature,
);
expect(await home.state()).to.equal(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(
home.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 home.dispatch(
localDomain,
abacus.ethersAddressToBytes32(signer.address),
message,
);
await home.checkpoint();
const [root, index] = await home.latestCheckpoint();
const { signature } = await validator.signCheckpoint(
root,
index.toNumber(),
);
// Send message with signer address as msg.sender
await expect(
validatorManager.improperCheckpoint(
home.address,
root,
index,
signature,
),
).to.be.revertedWith('!improper');
});
});
});