Skip to content

Commit

Permalink
feat(relay): Implement fallback node
Browse files Browse the repository at this point in the history
  • Loading branch information
Dimo99 committed Jun 29, 2023
1 parent 675574b commit abf680b
Show file tree
Hide file tree
Showing 13 changed files with 49 additions and 81 deletions.
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
**/*.ptau
**/*.wtns

**/*.log

**/artifacts
**/cache
**/.yarn
Expand Down
4 changes: 2 additions & 2 deletions beacon-light-client/circom/scripts/validator_balances/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { verifyMerkleProof } from '../../../../libs/typescript/ts-utils/ssz-util

(async () => {
const { ssz } = await import('@lodestar/types');
const beaconApi = new BeaconApi(
const beaconApi = new BeaconApi([
'http://unstable.prater.beacon-api.nimbus.team/',
);
]);

const beaconStateSZZ = await fetch(
`http://testing.mainnet.beacon-api.nimbus.team/eth/v2/debug/beacon/states/6616005`,
Expand Down
2 changes: 1 addition & 1 deletion beacon-light-client/solidity/tasks/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ task('deploy', 'Deploy the beacon light client contract')
console.log('Deploying contracts with the account:', deployer.address);
console.log('Account balance:', (await deployer.getBalance()).toString());

const beaconApi = new BeaconApi([currentConfig.BEACON_REST_API]);
const beaconApi = new BeaconApi(currentConfig.BEACON_REST_API);

const beaconLightClient = await (
await ethers.getContractFactory('BeaconLightClient')
Expand Down
10 changes: 5 additions & 5 deletions beacon-light-client/solidity/tasks/run-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ task('run-update', 'Run update recuring task')
const redis = new Redis(config.REDIS_HOST!, config.REDIS_PORT);

const lastDownloadedUpdateKey = !args.lightclient
? `lastDownloadedUpdateKey:${currentConfig.BEACON_REST_API}`
: `lastDownloadedUpdateKey:${currentConfig.BEACON_REST_API}:${args.lightclient}`;
? `lastDownloadedUpdateKey:${args.follownetwork}`
: `lastDownloadedUpdateKey:${args.follownetwork}:${args.lightclient}`;

const downloadUpdate = !args.lightclient
? `downloadUpdate${currentConfig.BEACON_REST_API}`
: `downloadUpdate${currentConfig.BEACON_REST_API}${args.lightclient}`;
? `downloadUpdate${args.follownetwork}`
: `downloadUpdate${args.follownetwork}${args.lightclient}`;

await redis.set(lastDownloadedUpdateKey, args.initialslot);

Expand All @@ -58,7 +58,7 @@ task('run-update', 'Run update recuring task')
downloadUpdate,
{
lastDownloadedUpdateKey: lastDownloadedUpdateKey,
beaconRestApi: currentConfig.BEACON_REST_API,
beaconRestApis: currentConfig.BEACON_REST_API,
slotsJump: Number(args.slotsjump),
networkConfig: currentConfig,
},
Expand Down
2 changes: 1 addition & 1 deletion beacon-light-client/solidity/tasks/start-publishing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ task('start-publishing', 'Run relayer')
}

const redis = new Redis(config.REDIS_HOST!, config.REDIS_PORT);
const beaconApi = new BeaconApi([currentConfig.BEACON_REST_API]);
const beaconApi = new BeaconApi(currentConfig.BEACON_REST_API);
const contract = new SolidityContract(
lightClientContract,
(network.config as any).url,
Expand Down
2 changes: 1 addition & 1 deletion beacon-light-client/solidity/tasks/verify-contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ task('verify-contracts', 'Verify')

const currentConfig = networkConfig[args.follownetwork] as Config;

const beaconApi = new BeaconApi([currentConfig.BEACON_REST_API!]);
const beaconApi = new BeaconApi(currentConfig.BEACON_REST_API!);

await run('verify:verify', {
address: args.lightclient,
Expand Down
1 change: 1 addition & 0 deletions contracts/cosmos/scripts/cosmos-publisher-script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ async function publishTask() {
rpcEndpoint,
network,
);

publishProofs(redis, beaconApi, contract);
}

Expand Down
5 changes: 3 additions & 2 deletions relay/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export type Config = {
FORK_VERSION: string;
DOMAIN_SYNC_COMMITTEE: string;
GENESIS_VALIDATORS_ROOT: string;
BEACON_REST_API: string;
BEACON_REST_API: string[];
};

export const PRATER: Config = {
Expand All @@ -16,8 +16,9 @@ export const PRATER: Config = {
DOMAIN_SYNC_COMMITTEE: '0x07000000',
GENESIS_VALIDATORS_ROOT:
'0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb',
BEACON_REST_API:
BEACON_REST_API: [
'https://purple-falling-tree.ethereum-goerli.discover.quiknode.pro/',
],
};

export const UPDATE_POLING_QUEUE = 'update_poling';
Expand Down
4 changes: 2 additions & 2 deletions relay/constants/network_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"FORK_VERSION": "0x03001020",
"DOMAIN_SYNC_COMMITTEE": "0x07000000",
"GENESIS_VALIDATORS_ROOT": "0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb",
"BEACON_REST_API": "https://purple-falling-tree.ethereum-goerli.discover.quiknode.pro/d713736b8470338a3cc2d45ed723d53e63b2032c"
"BEACON_REST_API": ["https://purple-falling-tree.ethereum-goerli.discover.quiknode.pro/d713736b8470338a3cc2d45ed723d53e63b2032c", "https://unstable.prater.beacon-api.nimbus.team"]
},
"mainnet": {
"SLOTS_PER_EPOCH": 32,
Expand All @@ -15,6 +15,6 @@
"FORK_VERSION": "0x03000000",
"DOMAIN_SYNC_COMMITTEE": "0x07000000",
"GENESIS_VALIDATORS_ROOT": "0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95",
"BEACON_REST_API": "http://unstable.mainnet.beacon-api.nimbus.team"
"BEACON_REST_API": ["http://unstable.mainnet.beacon-api.nimbus.team"]
}
}
66 changes: 24 additions & 42 deletions relay/implementations/beacon-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ export class BeaconApi implements IBeaconApi {
blockHashProof: string[];
}> {
const currentBlock = await (
await this.fetchWithFallback(
this.concatUrl(`/eth/v2/beacon/blocks/${slot}`),
)
await this.fetchWithFallback(`/eth/v2/beacon/blocks/${slot}`)
).json();

const { ssz } = await import('@lodestar/types');
Expand Down Expand Up @@ -82,19 +80,15 @@ export class BeaconApi implements IBeaconApi {

async getCurrentHeadSlot(): Promise<number> {
const currentHead = await (
await this.fetchWithFallback(
this.concatUrl('/eth/v1/beacon/headers/head'),
)
await this.fetchWithFallback('/eth/v1/beacon/headers/head')
).json();

return Number(currentHead.data.header.message.slot);
}

async getBlockSlot(blockHash: string): Promise<number> {
const headResult = await (
await this.fetchWithFallback(
this.concatUrl(`/eth/v1/beacon/headers/${blockHash}`),
)
await this.fetchWithFallback(`/eth/v1/beacon/headers/${blockHash}`)
).json();

return Number(headResult.data.header.message.slot);
Expand All @@ -112,9 +106,7 @@ export class BeaconApi implements IBeaconApi {
const { ssz } = await import('@lodestar/types');

const headResult = await (
await this.fetchWithFallback(
this.concatUrl(`/eth/v1/beacon/headers/${slot}`),
)
await this.fetchWithFallback(`/eth/v1/beacon/headers/${slot}`)
).json();

return ssz.phase0.BeaconBlockHeader.fromJson(
Expand All @@ -140,9 +132,7 @@ export class BeaconApi implements IBeaconApi {

while (slot <= limitSlot) {
blockHeaderResult = await (
await this.fetchWithFallback(
this.concatUrl(`/eth/v1/beacon/headers/${slot}`),
)
await this.fetchWithFallback(`/eth/v1/beacon/headers/${slot}`)
).json();

if (blockHeaderResult.code !== 404) {
Expand All @@ -167,9 +157,7 @@ export class BeaconApi implements IBeaconApi {

while (slot <= limitSlot) {
blockHeaderBodyResult = await (
await this.fetchWithFallback(
this.concatUrl(`/eth/v2/beacon/blocks/${slot}`),
)
await this.fetchWithFallback(`/eth/v2/beacon/blocks/${slot}`)
).json();

if (blockHeaderBodyResult.code !== 404) {
Expand Down Expand Up @@ -210,11 +198,9 @@ export class BeaconApi implements IBeaconApi {

const prevFinalizedHeaderResult = await (
await this.fetchWithFallback(
this.concatUrl(
`/eth/v1/beacon/headers/${
'0x' + bytesToHex(prevBeaconSate.finalizedCheckpoint.root)
}`,
),
`/eth/v1/beacon/headers/${
'0x' + bytesToHex(prevBeaconSate.finalizedCheckpoint.root)
}`,
)
).json();

Expand Down Expand Up @@ -290,11 +276,9 @@ export class BeaconApi implements IBeaconApi {

const finalizedHeaderResult = await (
await this.fetchWithFallback(
this.concatUrl(
`/eth/v1/beacon/headers/${
'0x' + bytesToHex(beaconState.finalizedCheckpoint.root)
}`,
),
`/eth/v1/beacon/headers/${
'0x' + bytesToHex(beaconState.finalizedCheckpoint.root)
}`,
)
).json();

Expand All @@ -319,9 +303,7 @@ export class BeaconApi implements IBeaconApi {
const { ssz } = await import('@lodestar/types');

const finalizedBlockBodyResult = await (
await this.fetchWithFallback(
this.concatUrl(`/eth/v2/beacon/blocks/${slot}`),
)
await this.fetchWithFallback(`/eth/v2/beacon/blocks/${slot}`)
).json();

const finalizedBlockBody = ssz.capella.BeaconBlockBody.fromJson(
Expand Down Expand Up @@ -362,15 +344,13 @@ export class BeaconApi implements IBeaconApi {

const finality_checkpoints = await (
await this.fetchWithFallback(
this.concatUrl(`/eth/v1/beacon/states/${slot}/finality_checkpoints`),
`/eth/v1/beacon/states/${slot}/finality_checkpoints`,
)
).json();

const finalizedHeadResult = await (
await this.fetchWithFallback(
this.concatUrl(
`/eth/v1/beacon/headers/${finality_checkpoints.data.finalized.root}`,
),
`/eth/v1/beacon/headers/${finality_checkpoints.data.finalized.root}`,
)
).json();

Expand All @@ -381,9 +361,7 @@ export class BeaconApi implements IBeaconApi {

async getExecutionStateRoot(slot: number): Promise<string> {
const block = await (
await this.fetchWithFallback(
this.concatUrl(`/eth/v2/beacon/blocks/${slot}`),
)
await this.fetchWithFallback(`/eth/v2/beacon/blocks/${slot}`)
).json();

return block.data.message.body.execution_payload.state_root;
Expand All @@ -393,7 +371,7 @@ export class BeaconApi implements IBeaconApi {
const { ssz } = await import('@lodestar/types');

const beaconStateSZZ = await this.fetchWithFallback(
this.concatUrl(`/eth/v2/debug/beacon/states/${slot}`),
`/eth/v2/debug/beacon/states/${slot}`,
{
headers: {
Accept: 'application/octet-stream',
Expand All @@ -420,19 +398,23 @@ export class BeaconApi implements IBeaconApi {
}

private async fetchWithFallback(
input: RequestInfo | URL,
subUrl: string,
init?: RequestInit,
): Promise<Response> {
let retries = 0;
while (true) {
try {
return await fetch(input, init);
return await fetch(this.concatUrl(subUrl), init);
} catch (error) {
retries++;
if (retries >= this.beaconRestApis.length) {
console.log('All beacon rest apis failed');
throw error;
}

retries++;
console.log('Beacon rest api failed:', error);

console.log('Retrying with the next one');

this.nextApi();
}
Expand Down
10 changes: 5 additions & 5 deletions relay/on_chain_publisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export async function publishProofs(
redis: IRedis,
beaconApi: IBeaconApi,
smartContract: ISmartContract,
hashiAdapterContract: Contract | undefined,
rpcEndpoint: string,
hashiAdapterContract?: Contract | undefined,
rpcEndpoint?: string,
transactionSpeed: TransactionSpeed = 'avg',
) {
try {
Expand Down Expand Up @@ -56,7 +56,7 @@ export async function drainUpdatesInRedis(
beaconApi: IBeaconApi,
smartContract: ISmartContract,
hashiAdapterContract: Contract | undefined,
rpcEndpoint: string,
rpcEndpoint?: string,
transactionSpeed: TransactionSpeed = 'avg',
) {
if (isDrainRunning) {
Expand Down Expand Up @@ -118,7 +118,7 @@ export async function postUpdateOnChain(
beaconApi: IBeaconApi,
lastSlotOnChain: number,
hashiAdapterContract: Contract | undefined,
rpcEndpoint: string,
rpcEndpoint?: string,
transactionSpeed: TransactionSpeed = 'avg',
) {
const update = {
Expand Down Expand Up @@ -165,7 +165,7 @@ export async function postUpdateOnChain(
hashiInfo.blockHashProof.map(x => '0x' + x),
{ ...update, ...solidityProof },
],
new Web3(rpcEndpoint),
new Web3(rpcEndpoint!),
transactionSpeed,
true,
);
Expand Down
2 changes: 1 addition & 1 deletion relay/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export interface UpdateResult {

export interface GetUpdate {
lastDownloadedUpdateKey: string;
beaconRestApi: string;
beaconRestApis: string[];
slotsJump: number;
networkConfig: Config;
}
Expand Down
20 changes: 1 addition & 19 deletions relay/workers/poll-updates/poll-updates-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,30 +30,12 @@ import { checkConfig } from '../../../libs/typescript/ts-utils/common-utils';
updatePollingConfig.REDIS_PORT,
);

const updateQueue = new Queue<GetUpdate>(UPDATE_POLING_QUEUE, {
connection: {
host: updatePollingConfig.REDIS_HOST!,
port: updatePollingConfig.REDIS_PORT,
},
});

const activeJobs = await updateQueue.getActive();

new Worker<GetUpdate>(
UPDATE_POLING_QUEUE,
async job => {
for (let activeJob of activeJobs) {
if (
activeJob.data.beaconRestApi == job.data.beaconRestApi &&
activeJob.data.slotsJump == job.data.slotsJump
) {
return;
}
}

doUpdate(
redis,
new BeaconApi([job.data.beaconRestApi]),
new BeaconApi(job.data.beaconRestApis),
proofGenertorQueue,
job.data.lastDownloadedUpdateKey,
job.data.slotsJump,
Expand Down

0 comments on commit abf680b

Please sign in to comment.