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.
200 lines
6.2 KiB
200 lines
6.2 KiB
3 years ago
|
import { assert } from 'chai';
|
||
|
import * as ethers from 'ethers';
|
||
3 years ago
|
import { types } from '@abacus-network/utils';
|
||
3 years ago
|
|
||
3 years ago
|
import { Validator } from './core';
|
||
3 years ago
|
|
||
|
import {
|
||
3 years ago
|
TestOutbox,
|
||
|
TestOutbox__factory,
|
||
3 years ago
|
ValidatorManager,
|
||
|
ValidatorManager__factory,
|
||
3 years ago
|
UpgradeBeaconController,
|
||
|
UpgradeBeaconController__factory,
|
||
|
XAppConnectionManager,
|
||
|
XAppConnectionManager__factory,
|
||
3 years ago
|
TestInbox,
|
||
|
TestInbox__factory,
|
||
3 years ago
|
} from '../../types';
|
||
3 years ago
|
|
||
|
export interface AbacusInstance {
|
||
|
domain: types.Domain;
|
||
3 years ago
|
validator: Validator;
|
||
|
validatorManager: ValidatorManager;
|
||
3 years ago
|
outbox: TestOutbox;
|
||
3 years ago
|
connectionManager: XAppConnectionManager;
|
||
|
ubc: UpgradeBeaconController;
|
||
3 years ago
|
inboxs: Record<number, TestInbox>;
|
||
3 years ago
|
}
|
||
|
|
||
|
export class AbacusDeployment {
|
||
|
constructor(
|
||
|
public readonly domains: types.Domain[],
|
||
|
public readonly instances: Record<number, AbacusInstance>,
|
||
|
public readonly signer: ethers.Signer,
|
||
|
) {}
|
||
|
|
||
|
static async fromDomains(domains: types.Domain[], signer: ethers.Signer) {
|
||
|
const instances: Record<number, AbacusInstance> = {};
|
||
|
for (const local of domains) {
|
||
|
const instance = await AbacusDeployment.deployInstance(
|
||
|
local,
|
||
|
domains.filter((d) => d !== local),
|
||
|
signer,
|
||
|
);
|
||
|
instances[local] = instance;
|
||
|
}
|
||
|
return new AbacusDeployment(domains, instances, signer);
|
||
|
}
|
||
|
|
||
|
static async deployInstance(
|
||
|
local: types.Domain,
|
||
|
remotes: types.Domain[],
|
||
|
signer: ethers.Signer,
|
||
|
): Promise<AbacusInstance> {
|
||
3 years ago
|
const validatorManagerFactory = new ValidatorManager__factory(signer);
|
||
|
const validatorManager = await validatorManagerFactory.deploy();
|
||
3 years ago
|
await validatorManager.enrollValidator(local, await signer.getAddress());
|
||
3 years ago
|
await Promise.all(
|
||
|
remotes.map(async (remoteDomain) =>
|
||
3 years ago
|
validatorManager.enrollValidator(
|
||
|
remoteDomain,
|
||
|
await signer.getAddress(),
|
||
|
),
|
||
3 years ago
|
),
|
||
3 years ago
|
);
|
||
|
|
||
|
const ubcFactory = new UpgradeBeaconController__factory(signer);
|
||
|
const ubc = await ubcFactory.deploy();
|
||
|
|
||
3 years ago
|
const outboxFactory = new TestOutbox__factory(signer);
|
||
|
const outbox = await outboxFactory.deploy(local);
|
||
|
await outbox.initialize(validatorManager.address);
|
||
3 years ago
|
|
||
|
const connectionManagerFactory = new XAppConnectionManager__factory(signer);
|
||
|
const connectionManager = await connectionManagerFactory.deploy();
|
||
3 years ago
|
await connectionManager.setOutbox(outbox.address);
|
||
3 years ago
|
|
||
3 years ago
|
const inboxFactory = new TestInbox__factory(signer);
|
||
|
const inboxs: Record<number, TestInbox> = {};
|
||
3 years ago
|
const deploys = remotes.map(async (remoteDomain) => {
|
||
3 years ago
|
const inbox = await inboxFactory.deploy(local);
|
||
3 years ago
|
await inbox.initialize(
|
||
3 years ago
|
remoteDomain,
|
||
3 years ago
|
validatorManager.address,
|
||
3 years ago
|
ethers.constants.HashZero,
|
||
3 years ago
|
0,
|
||
3 years ago
|
);
|
||
3 years ago
|
await connectionManager.enrollInbox(remoteDomain, inbox.address);
|
||
3 years ago
|
inboxs[remoteDomain] = inbox;
|
||
3 years ago
|
});
|
||
|
await Promise.all(deploys);
|
||
|
return {
|
||
|
domain: local,
|
||
3 years ago
|
validator: await Validator.fromSigner(signer, local),
|
||
3 years ago
|
outbox,
|
||
3 years ago
|
connectionManager,
|
||
3 years ago
|
validatorManager,
|
||
3 years ago
|
inboxs,
|
||
3 years ago
|
ubc,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
async transferOwnership(domain: types.Domain, address: types.Address) {
|
||
3 years ago
|
await this.outbox(domain).transferOwnership(address);
|
||
3 years ago
|
await this.ubc(domain).transferOwnership(address);
|
||
|
await this.connectionManager(domain).transferOwnership(address);
|
||
3 years ago
|
await this.validatorManager(domain).transferOwnership(address);
|
||
3 years ago
|
for (const remote of this.domains) {
|
||
|
if (remote !== domain) {
|
||
3 years ago
|
await this.inbox(domain, remote).transferOwnership(address);
|
||
3 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
3 years ago
|
outbox(domain: types.Domain): TestOutbox {
|
||
|
return this.instances[domain].outbox;
|
||
3 years ago
|
}
|
||
|
|
||
|
ubc(domain: types.Domain): UpgradeBeaconController {
|
||
|
return this.instances[domain].ubc;
|
||
|
}
|
||
|
|
||
3 years ago
|
validator(domain: types.Domain): Validator {
|
||
|
return this.instances[domain].validator;
|
||
3 years ago
|
}
|
||
|
|
||
3 years ago
|
inbox(local: types.Domain, remote: types.Domain): TestInbox {
|
||
|
return this.instances[local].inboxs[remote];
|
||
3 years ago
|
}
|
||
|
|
||
|
connectionManager(domain: types.Domain): XAppConnectionManager {
|
||
|
return this.instances[domain].connectionManager;
|
||
|
}
|
||
|
|
||
3 years ago
|
validatorManager(domain: types.Domain): ValidatorManager {
|
||
|
return this.instances[domain].validatorManager;
|
||
3 years ago
|
}
|
||
|
|
||
|
async processMessages() {
|
||
|
await Promise.all(
|
||
|
this.domains.map((d) => this.processMessagesFromDomain(d)),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
async processMessagesFromDomain(local: types.Domain) {
|
||
3 years ago
|
const outbox = this.outbox(local);
|
||
3 years ago
|
const [checkpointedRoot, checkpointedIndex] =
|
||
|
await outbox.latestCheckpoint();
|
||
|
const latestIndex = await outbox.tree();
|
||
|
if (latestIndex.eq(checkpointedIndex)) return;
|
||
3 years ago
|
|
||
3 years ago
|
// Find the block number of the last checkpoint submitted on Outbox.
|
||
|
const checkpointFilter = outbox.filters.Checkpoint(checkpointedRoot);
|
||
|
const checkpoints = await outbox.queryFilter(checkpointFilter);
|
||
3 years ago
|
assert(checkpoints.length === 0 || checkpoints.length === 1);
|
||
|
const fromBlock = checkpoints.length === 0 ? 0 : checkpoints[0].blockNumber;
|
||
|
|
||
3 years ago
|
await outbox.checkpoint();
|
||
|
const [root, index] = await outbox.latestCheckpoint();
|
||
3 years ago
|
// If there have been no checkpoints since the last checkpoint, return.
|
||
|
if (
|
||
|
index.eq(0) ||
|
||
|
(checkpoints.length == 1 && index.eq(checkpoints[0].args.index))
|
||
|
) {
|
||
|
return;
|
||
|
}
|
||
3 years ago
|
// Update the Outbox and Inboxs to the latest roots.
|
||
3 years ago
|
// This is technically not necessary given that we are not proving against
|
||
3 years ago
|
// a root in the TestInbox.
|
||
3 years ago
|
const validator = this.validator(local);
|
||
|
const { signature } = await validator.signCheckpoint(
|
||
|
root,
|
||
|
index.toNumber(),
|
||
|
);
|
||
3 years ago
|
|
||
|
for (const remote of this.domains) {
|
||
|
if (remote !== local) {
|
||
3 years ago
|
const inbox = this.inbox(remote, local);
|
||
|
await inbox.checkpoint(root, index, signature);
|
||
3 years ago
|
}
|
||
|
}
|
||
|
|
||
3 years ago
|
// Find all messages dispatched on the outbox since the previous checkpoint.
|
||
|
const dispatchFilter = outbox.filters.Dispatch();
|
||
|
const dispatches = await outbox.queryFilter(dispatchFilter, fromBlock);
|
||
3 years ago
|
for (const dispatch of dispatches) {
|
||
|
const destination = dispatch.args.destinationAndNonce.shr(32).toNumber();
|
||
|
if (destination !== local) {
|
||
3 years ago
|
const inbox = this.inbox(destination, local);
|
||
|
await inbox.setMessageProven(dispatch.args.message);
|
||
|
await inbox.testProcess(dispatch.args.message);
|
||
3 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export const abacus: any = {
|
||
|
AbacusDeployment,
|
||
|
};
|