diff --git a/ironfish-cli/src/commands/ceremony/contributions.ts b/ironfish-cli/src/commands/ceremony/contributions.ts new file mode 100644 index 0000000000..0603987f5c --- /dev/null +++ b/ironfish-cli/src/commands/ceremony/contributions.ts @@ -0,0 +1,65 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { S3Client } from '@aws-sdk/client-s3' +import { Flags } from '@oclif/core' +import { IronfishCommand } from '../../command' +import { S3Utils } from '../../utils' + +export default class CeremonyContributions extends IronfishCommand { + static description = 'List all the current contributions with names' + + static flags = { + start: Flags.integer({ + required: false, + }), + end: Flags.integer({ + required: false, + }), + } + + async start(): Promise { + const { flags } = await this.parse(CeremonyContributions) + + const r2Credentials = await S3Utils.getR2Credentials() + + if (r2Credentials === undefined) { + this.logger.log('Failed getting R2 credentials from AWS') + this.exit(0) + return + } + + const r2Client = S3Utils.getR2S3Client(r2Credentials) + + const latestParamName = await this.getLatestParamName(r2Client, 'ironfish-contributions') + const latestParamNumber = parseInt(latestParamName.split('_')[1]) + const keys: string[] = [...new Array(latestParamNumber + 1)] + .map((_, i) => i) + .filter((i) => (!flags.start || i >= flags.start) && (!flags.end || i <= flags.end)) + .map((i) => { + return 'params_' + i.toString().padStart(5, '0') + }) + + for (const key of keys) { + const { Metadata } = await S3Utils.getObjectMetadata( + r2Client, + 'ironfish-contributions', + key, + ) + this.log( + `Contribution: ${key.split('_')[1]}, Name: ${Metadata?.contributorName || '-'}, IP: ${ + Metadata?.remoteaddress || '-' + }`, + ) + } + } + + async getLatestParamName(client: S3Client, bucket: string): Promise { + const paramFileNames = await S3Utils.getBucketObjects(client, bucket) + const validParams = paramFileNames + .slice(0) + .filter((fileName) => /^params_\d{5}$/.test(fileName)) + validParams.sort() + return validParams[validParams.length - 1] + } +} diff --git a/ironfish-cli/src/commands/ceremony.ts b/ironfish-cli/src/commands/ceremony/index.ts similarity index 98% rename from ironfish-cli/src/commands/ceremony.ts rename to ironfish-cli/src/commands/ceremony/index.ts index 53cdf21762..ab24059f59 100644 --- a/ironfish-cli/src/commands/ceremony.ts +++ b/ironfish-cli/src/commands/ceremony/index.ts @@ -8,9 +8,9 @@ import axios from 'axios' import fsAsync from 'fs/promises' import path from 'path' import { pipeline } from 'stream/promises' -import { IronfishCommand } from '../command' -import { DataDirFlag, DataDirFlagKey, VerboseFlag, VerboseFlagKey } from '../flags' -import { CeremonyClient } from '../trusted-setup/client' +import { IronfishCommand } from '../../command' +import { DataDirFlag, DataDirFlagKey, VerboseFlag, VerboseFlagKey } from '../../flags' +import { CeremonyClient } from '../../trusted-setup/client' export default class Ceremony extends IronfishCommand { static description = 'Contribute randomness to the Iron Fish trusted setup' diff --git a/ironfish-cli/src/commands/service/ceremony.ts b/ironfish-cli/src/commands/ceremony/service.ts similarity index 96% rename from ironfish-cli/src/commands/service/ceremony.ts rename to ironfish-cli/src/commands/ceremony/service.ts index f327301356..b5991d6bbe 100644 --- a/ironfish-cli/src/commands/service/ceremony.ts +++ b/ironfish-cli/src/commands/ceremony/service.ts @@ -13,7 +13,7 @@ const UPLOAD_TIMEOUT_MS = 5 * 60 * 1000 const PRESIGNED_EXPIRATION_SEC = 5 * 60 const START_DATE = 1681146000000 // Monday, April 10, 2023 10:00:00 AM GMT-07:00 (Pacific Daylight Time) -export default class Ceremony extends IronfishCommand { +export default class CeremonyService extends IronfishCommand { static hidden = true static description = ` @@ -68,7 +68,7 @@ export default class Ceremony extends IronfishCommand { } async start(): Promise { - const { flags } = await this.parse(Ceremony) + const { flags } = await this.parse(CeremonyService) const DEFAULT_HOST = '0.0.0.0' const DEFAULT_PORT = 9040 diff --git a/ironfish-cli/src/utils/s3.ts b/ironfish-cli/src/utils/s3.ts index 429a85e837..bbe1d4a836 100644 --- a/ironfish-cli/src/utils/s3.ts +++ b/ironfish-cli/src/utils/s3.ts @@ -11,6 +11,8 @@ import { DeleteObjectCommand, DeleteObjectCommandOutput, GetObjectCommand, + HeadObjectCommand, + HeadObjectCommandOutput, ListObjectsCommand, ListObjectsCommandInput, PutObjectCommand, @@ -263,6 +265,16 @@ export function getDownloadUrl( return `https://${bucket}.${regionString}.amazonaws.com/${key}` } +export async function getObjectMetadata( + s3: S3Client, + bucket: string, + key: string, +): Promise { + const command = new HeadObjectCommand({ Bucket: bucket, Key: key }) + const response = await s3.send(command) + return response +} + export async function getBucketObjects(s3: S3Client, bucket: string): Promise { let truncated = true let commandParams: ListObjectsCommandInput = { Bucket: bucket }