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

feat: 5076 v11 lh propose signs payloads #5144

Merged
merged 21 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-test-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ jobs:
run: yarn workspace @connext/smart-contracts forge:install

- name: Yarn build
run: yarn build
run: yarn build:all

- name: Install DBMate
run: sudo curl -fsSL -o /usr/local/bin/dbmate https://github.com/amacneil/dbmate/releases/latest/download/dbmate-linux-amd64 && sudo chmod +x /usr/local/bin/dbmate
Expand Down
26 changes: 26 additions & 0 deletions packages/adapters/database/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,17 @@ export const getCurrentFinalizedSnapshot = async (
return snapshot ? convertFromDbSnapshot(snapshot) : undefined;
};

export const getLatestSnapshot = async (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure where this helper is used, in LH.

_pool?: Pool | db.TxnClientForRepeatableRead,
): Promise<Snapshot | undefined> => {
const poolToUse = _pool ?? pool;

const snapshot = await db
.selectOne("snapshots", {}, { limit: 1, order: { by: "id", direction: "DESC" } })
.run(poolToUse);
return snapshot ? convertFromDbSnapshot(snapshot) : undefined;
};

export const getCurrentProposedOptimisticRoot = async (
domain: string,
_pool?: Pool | db.TxnClientForRepeatableRead,
Expand Down Expand Up @@ -1138,6 +1149,21 @@ export const getLatestFinalizedOptimisticRoot = async (
return opRoot ? convertFromDbSpokeOptimisticRoot(opRoot) : undefined;
};

export const getLatestSpokeOptimisticRoot = async (
domain: string,
_pool?: Pool | db.TxnClientForRepeatableRead,
): Promise<SpokeOptimisticRoot | undefined> => {
const poolToUse = _pool ?? pool;
const opRoot = await db
.selectOne(
"spoke_optimistic_roots",
{ domain },
{ limit: 1, order: { by: "propose_timestamp", direction: "DESC" } },
)
.run(poolToUse);
return opRoot ? convertFromDbSpokeOptimisticRoot(opRoot) : undefined;
};

export const getSpokeOptimisticRoot = async (
root: string,
domain: string,
Expand Down
11 changes: 11 additions & 0 deletions packages/adapters/database/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import {
getAggregateRoot,
getCurrentProposedSnapshot,
getCurrentFinalizedSnapshot,
getLatestSnapshot,
getLatestPendingSnapshotRootByDomain,
getMessageRootAggregatedFromIndex,
getMessageRootsFromIndex,
Expand Down Expand Up @@ -104,6 +105,7 @@ import {
saveFinalizedSpokeRoots,
getCurrentProposedOptimisticRoot,
getLatestFinalizedOptimisticRoot,
getLatestSpokeOptimisticRoot,
getSpokeOptimisticRoot,
} from "./client";

Expand Down Expand Up @@ -221,6 +223,7 @@ export type Database = {
getBaseAggregateRoot: (_pool?: Pool | TxnClientForRepeatableRead) => Promise<string | undefined>;
getCurrentProposedSnapshot: (_pool?: Pool | TxnClientForRepeatableRead) => Promise<Snapshot | undefined>;
getCurrentFinalizedSnapshot: (_pool?: Pool | TxnClientForRepeatableRead) => Promise<Snapshot | undefined>;
getLatestSnapshot: (_pool?: Pool | TxnClientForRepeatableRead) => Promise<Snapshot | undefined>;
getMessageRootIndex: (
domain: string,
messageRoot: string,
Expand Down Expand Up @@ -363,6 +366,10 @@ export type Database = {
domain: string,
_pool?: Pool | TxnClientForRepeatableRead,
) => Promise<SpokeOptimisticRoot | undefined>;
getLatestSpokeOptimisticRoot: (
domain: string,
_pool?: Pool | TxnClientForRepeatableRead,
) => Promise<SpokeOptimisticRoot | undefined>;
getSpokeOptimisticRoot: (
root: string,
domain: string,
Expand Down Expand Up @@ -426,6 +433,7 @@ export const getDatabase = async (databaseUrl: string, logger: Logger): Promise<
getAggregateRoot,
getCurrentProposedSnapshot,
getCurrentFinalizedSnapshot,
getLatestSnapshot,
getLatestPendingSnapshotRootByDomain,
getMessageRootAggregatedFromIndex,
getMessageRootsFromIndex,
Expand Down Expand Up @@ -458,6 +466,7 @@ export const getDatabase = async (databaseUrl: string, logger: Logger): Promise<
saveFinalizedSpokeRoots,
getCurrentProposedOptimisticRoot,
getLatestFinalizedOptimisticRoot,
getLatestSpokeOptimisticRoot,
getSpokeOptimisticRoot,
};
};
Expand Down Expand Up @@ -522,6 +531,7 @@ export const getDatabaseAndPool = async (
getAggregateRoot,
getCurrentProposedSnapshot,
getCurrentFinalizedSnapshot,
getLatestSnapshot,
getLatestPendingSnapshotRootByDomain,
getMessageRootAggregatedFromIndex,
getMessageRootsFromIndex,
Expand Down Expand Up @@ -554,6 +564,7 @@ export const getDatabaseAndPool = async (
saveFinalizedSpokeRoots,
getCurrentProposedOptimisticRoot,
getLatestFinalizedOptimisticRoot,
getLatestSpokeOptimisticRoot,
getSpokeOptimisticRoot,
},
};
Expand Down
17 changes: 15 additions & 2 deletions packages/adapters/database/test/client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ import {
getAggregateRoots,
getCurrentProposedOptimisticRoot,
getLatestFinalizedOptimisticRoot,
getLatestSpokeOptimisticRoot,
getSpokeOptimisticRoot,
saveSnapshotRoots,
getLatestPendingSnapshotRootByDomain,
Expand All @@ -101,6 +102,7 @@ import {
savePropagatedOptimisticRoots,
getCurrentProposedSnapshot,
getCurrentFinalizedSnapshot,
getLatestSnapshot,
saveFinalizedRoots,
saveStableSwapExchange,
saveRouterDailyTVL,
Expand Down Expand Up @@ -1140,6 +1142,7 @@ describe("Database client", () => {
await expect(getFinalizedSnapshot(undefined as any, undefined as any)).to.eventually.not.be.rejected;
await expect(getCurrentProposedOptimisticRoot(undefined as any, undefined as any)).to.eventually.not.be.rejected;
await expect(getLatestFinalizedOptimisticRoot(undefined as any, undefined as any)).to.eventually.not.be.rejected;
await expect(getLatestSpokeOptimisticRoot(undefined as any, undefined as any)).to.eventually.not.be.rejected;
await expect(getSpokeOptimisticRoot(undefined as any, undefined as any)).to.eventually.not.be.rejected;
await expect(getAggregateRootCount(undefined as any, undefined as any)).to.eventually.not.be.rejected;
await expect(getBaseAggregateRootCount(undefined as any, undefined as any)).to.eventually.not.be.rejected;
Expand Down Expand Up @@ -1631,6 +1634,9 @@ describe("Database client", () => {

const propagagtedSnapshot = await getCurrentFinalizedSnapshot(pool);
expect(propagagtedSnapshot!.id).to.eq(snapshots[batchSize - 1].id);

const latestSnapshot = await getLatestSnapshot(pool);
expect(latestSnapshot!.id).to.eq(snapshots[batchSize - 1].id);
});

it("should save and get Propagated snapshots", async () => {
Expand Down Expand Up @@ -1690,15 +1696,22 @@ describe("Database client", () => {
const m = mock.entity.spokeOptimisticRoot();
m.id = `${_i}`;
m.rootTimestamp = _i;
m.proposeTimestamp = _i;
spokeOptimisticRoots.push(m);
}
await saveProposedSpokeRoots(spokeOptimisticRoots, pool);

const latestSpokeRoot = await getCurrentProposedOptimisticRoot(spokeOptimisticRoots[batchSize - 1].domain, pool);
expect(latestSpokeRoot!.id).to.eq(spokeOptimisticRoots[batchSize - 1].id);
const latestProposedSpokeRoot = await getCurrentProposedOptimisticRoot(
spokeOptimisticRoots[batchSize - 1].domain,
pool,
);
expect(latestProposedSpokeRoot!.id).to.eq(spokeOptimisticRoots[batchSize - 1].id);

const missingDbSpokeRoot = await getLatestPendingSpokeOptimisticRootByDomain("", pool);
expect(missingDbSpokeRoot).to.eq(undefined);

const latestSpokeRoot = await getLatestSpokeOptimisticRoot(spokeOptimisticRoots[batchSize - 1].domain, pool);
expect(latestSpokeRoot!.id).to.eq(spokeOptimisticRoots[batchSize - 1].id);
});

it("should save and get finalized spoke optimistic roots", async () => {
Expand Down
2 changes: 2 additions & 0 deletions packages/adapters/database/test/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export const mockDatabase = (): Database => {
saveSnapshotRoots: stub().resolves(),
getCurrentProposedSnapshot: stub().resolves(),
getCurrentFinalizedSnapshot: stub().resolves(),
getLatestSnapshot: stub().resolves(),
getBaseAggregateRoot: stub().resolves(),
getAggregateRoots: stub().resolves(),
getAggregateRoot: stub().resolves(),
Expand All @@ -90,6 +91,7 @@ export const mockDatabase = (): Database => {
getLatestPendingSnapshotRootByDomain: stub().resolves([mock.entity.snapshotRoot()]),
getCurrentProposedOptimisticRoot: stub().resolves([mock.entity.spokeOptimisticRoot()]),
getLatestFinalizedOptimisticRoot: stub().resolves([mock.entity.spokeOptimisticRoot()]),
getLatestSpokeOptimisticRoot: stub().resolves([mock.entity.spokeOptimisticRoot()]),
getSpokeOptimisticRoot: stub().resolves([mock.entity.spokeOptimisticRoot()]),
getLatestPendingSpokeOptimisticRootByDomain: stub().resolves(),
saveProposedSpokeRoots: stub().resolves(),
Expand Down
3 changes: 3 additions & 0 deletions packages/agents/lighthouse/.nycrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
"src/tasks/sendOutboundRoot/sendOutboundRoot.ts",
"src/tasks/sendOutboundRoot/operations/index.ts",
"src/tasks/sendOutboundRoot/helpers/index.ts",
"src/tasks/propose/errors.ts",
"src/tasks/propose/context.ts",
"src/tasks/propose/index.ts",
"test/**/*.ts",
"./globalTestHook.ts"
]
Expand Down
1 change: 1 addition & 0 deletions packages/agents/lighthouse/config.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"databaseWriter": {
"url": "postgres://postgres:postgres@localhost:5432/connext?sslmode=disable"
},
"mnemonic": "test test test test test test test test test test test test",
"relayers": [
{
"type": "Gelato",
Expand Down
8 changes: 8 additions & 0 deletions packages/agents/lighthouse/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ export const NxtpLighthouseConfigSchema = Type.Object({
environment: Type.Union([Type.Literal("staging"), Type.Literal("production")]),
database: TDatabaseConfig,
databaseWriter: TDatabaseConfig,
mnemonic: Type.Optional(Type.String()),
web3SignerUrl: Type.Optional(Type.String()),
redis: TRedisConfig,
subgraphPrefix: Type.Optional(Type.String()),
healthUrls: Type.Partial(
Expand Down Expand Up @@ -203,6 +205,8 @@ export const getEnvConfig = (
? +process.env.REDIS_PORT
: undefined || configJson.redis?.port || configFile.redis?.port || 6379,
},
mnemonic: process.env.NXTP_MNEMONIC || configJson.mnemonic || configFile.mnemonic,
web3SignerUrl: process.env.NXTP_WEB3_SIGNER_URL || configJson.web3SignerUrl || configFile.web3SignerUrl,
environment: process.env.NXTP_ENVIRONMENT || configJson.environment || configFile.environment || "production",
cartographerUrl: process.env.NXTP_CARTOGRAPHER_URL || configJson.cartographerUrl || configFile.cartographerUrl,
subgraphPrefix: process.env.NXTP_SUBGRAPH_PREFIX || configJson.subgraphPrefix || configFile.subgraphPrefix,
Expand Down Expand Up @@ -252,6 +256,10 @@ export const getEnvConfig = (
? ""
: (`${nxtpConfig.environment[0].toUpperCase()}${nxtpConfig.environment.slice(1)}` as ContractPostfix);

if (!nxtpConfig.mnemonic && !nxtpConfig.web3SignerUrl) {
throw new Error(`Wallet missing, please add either mnemonic or web3SignerUrl: ${JSON.stringify(nxtpConfig)}`);
}

// add contract deployments if they exist
const hubChain = domainToChainId(+nxtpConfig.hubDomain);
Object.entries(nxtpConfig.chains).forEach(([domainId, chainConfig]) => {
Expand Down
3 changes: 3 additions & 0 deletions packages/agents/lighthouse/src/tasks/propagate/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { ChainData, Logger, RelayerType } from "@connext/nxtp-utils";
import { Relayer } from "@connext/nxtp-adapters-relayer";
import { SubgraphReader } from "@connext/nxtp-adapters-subgraph";
import { Database } from "@connext/nxtp-adapters-database";
import { Web3Signer } from "@connext/nxtp-adapters-web3signer";
import { Wallet } from "ethers";

import { NxtpLighthouseConfig } from "../../config";

Expand All @@ -22,6 +24,7 @@ export type PropagateContext = {
relayers: { instance: Relayer; apiKey: string; type: RelayerType }[];
subgraph: SubgraphReader; // Aggregates subgraphs in a FallbackSubgraph for each chain.
database: Database;
wallet: Wallet | Web3Signer; // Used for signing metatxs for propagate.
};
config: NxtpLighthouseConfig;
chainData: Map<string, ChainData>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ export const finalize = async () => {
throw new NoChainIdForDomain(config.hubDomain, requestContext, methodContext);
}

//TODO: V1.1 needs be relayer proxy hub
const rootManagerAddress = config.chains[config.hubDomain].deployments.rootManager;

const currentSnapshot = await database.getCurrentProposedSnapshot();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createLoggingContext, NxtpError } from "@connext/nxtp-utils";

import { sendWithRelayerWithBackup } from "../../../mockable";
import { NoChainIdForDomain, NoSpokeConnector } from "../errors";
import { NoChainIdForDomain } from "../errors";
import { getContext } from "../propagate";

export const finalizeSpoke = async (spokeDomain: string) => {
Expand All @@ -27,10 +27,6 @@ export const finalizeSpoke = async (spokeDomain: string) => {
}
const spokeConnectorAddress = config.chains[spokeDomain].deployments.spokeConnector;

if (!spokeConnectorAddress) {
throw new NoSpokeConnector(+spokeDomain, requestContext, methodContext);
}

const currentProposedRoot = await database.getCurrentProposedOptimisticRoot(spokeDomain);

if (!currentProposedRoot) {
Expand Down Expand Up @@ -75,8 +71,6 @@ export const finalizeSpoke = async (spokeDomain: string) => {
return;
}

// TODO: V1.1 Sign the proposal -- need signature from whitelisted proposer agent
// TODO: V1.1 Use relayerproxyhub to send tx ?
const encodedDataForRelayer = contracts.spokeConnector.encodeFunctionData("finalize", [
_proposedAggregateRoot,
_rootTimestamp,
Expand Down
6 changes: 6 additions & 0 deletions packages/agents/lighthouse/src/tasks/propagate/propagate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
} from "@connext/nxtp-utils";
import { setupConnextRelayer, setupGelatoRelayer } from "@connext/nxtp-adapters-relayer";
import { SubgraphReader } from "@connext/nxtp-adapters-subgraph";
import { Web3Signer } from "@connext/nxtp-adapters-web3signer";
import { Wallet } from "ethers";

import { NxtpLighthouseConfig } from "../../config";

Expand Down Expand Up @@ -52,6 +54,10 @@ export const makePropagate = async (config: NxtpLighthouseConfig, chainData: Map
);
context.adapters.database = await getDatabase(context.config.database.url, context.logger);

context.adapters.wallet = context.config.mnemonic
? Wallet.fromMnemonic(context.config.mnemonic)
: new Web3Signer(context.config.web3SignerUrl!);

context.adapters.relayers = [];
for (const relayerConfig of context.config.relayers) {
const setupFunc =
Expand Down
3 changes: 3 additions & 0 deletions packages/agents/lighthouse/src/tasks/propose/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { ChainData, Logger, RelayerType } from "@connext/nxtp-utils";
import { Relayer } from "@connext/nxtp-adapters-relayer";
import { SubgraphReader } from "@connext/nxtp-adapters-subgraph";
import { Database } from "@connext/nxtp-adapters-database";
import { Web3Signer } from "@connext/nxtp-adapters-web3signer";
import { Wallet } from "ethers";

import { NxtpLighthouseConfig } from "../../config";

Expand All @@ -22,6 +24,7 @@ export type ProposeContext = {
relayers: { instance: Relayer; apiKey: string; type: RelayerType }[];
subgraph: SubgraphReader; // Aggregates subgraphs in a FallbackSubgraph for each chain.
database: Database;
wallet: Wallet | Web3Signer; // Used for signing metatxs for propose.
};
config: NxtpLighthouseConfig;
chainData: Map<string, ChainData>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { proposeHub, proposeSnapshot, getCurrentOutboundRoot } from "./propose";
export { proposeHub, proposeSnapshot, getCurrentOutboundRoot } from "./proposeHub";
export { proposeSpoke } from "./proposeSpoke";
Loading