Skip to content

Commit

Permalink
feat: Add hub operator's FID (#1352)
Browse files Browse the repository at this point in the history
  • Loading branch information
adityapk00 committed Sep 7, 2023
1 parent aac4220 commit bc416db
Show file tree
Hide file tree
Showing 16 changed files with 191 additions and 14 deletions.
7 changes: 7 additions & 0 deletions .changeset/serious-students-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@farcaster/hub-nodejs": patch
"@farcaster/core": patch
"@farcaster/hubble": patch
---

feat: Allow Hub operators to set an FID
4 changes: 2 additions & 2 deletions apps/hubble/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ services:
"--l2-rpc-url", "$OPTIMISM_L2_RPC_URL",
"--network", "${FC_NETWORK_ID:-1}",
"-b", "${BOOTSTRAP_NODE:-/dns/nemes.farcaster.xyz/tcp/2282}",
"--statsd-metrics-server",
"$STATSD_METRICS_SERVER"
"--statsd-metrics-server", "$STATSD_METRICS_SERVER",
"--hub-operator-fid", "${HUB_OPERATOR_FID:-0}",
]
ports:
- '2282:2282' # Gossip
Expand Down
5 changes: 3 additions & 2 deletions apps/hubble/grafana/grafana-dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -699,10 +699,11 @@
"viz": false
},
"lineInterpolation": "stepBefore",
"lineWidth": 4,
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
"log": 2,
"type": "log"
},
"showPoints": "auto",
"spanNulls": true,
Expand Down
1 change: 1 addition & 0 deletions apps/hubble/scripts/clidocs.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = function clidocs() {
const docFileName = "www/docs/docs/cli.md";

try {
// Step 1: Get the list of all options from the CLI
const helpOutput = execSync("node --no-warnings build/cli.js start --help").toString();

const optionNames = [];
Expand Down
35 changes: 35 additions & 0 deletions apps/hubble/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { mainnet, optimism } from "viem/chains";
import { finishAllProgressBars } from "./utils/progressBars.js";
import { MAINNET_BOOTSTRAP_PEERS } from "./bootstrapPeers.mainnet.js";
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
import axios from "axios";

/** A CLI to accept options from the user and start the Hub */

Expand Down Expand Up @@ -71,6 +72,7 @@ app
// Hubble Options
.option("-n --network <network>", "ID of the Farcaster Network (default: 3 (devnet))", parseNetwork)
.option("-i, --id <filepath>", "Path to the PeerId file.")
.option("--hub-operator-fid <fid>", "The FID of the hub operator")
.option("-c, --config <filepath>", "Path to the config file.")
.option("--db-name <name>", "The name of the RocksDB instance. (default: rocks.hub._default)")
.option("--admin-server-enabled", "Enable the admin server. (default: disabled)")
Expand Down Expand Up @@ -523,8 +525,41 @@ app
disableSnapshotSync: cliOptions.disableSnapshotSync ?? hubConfig.disableSnapshotSync ?? false,
enableSnapshotToS3,
s3SnapshotBucket: cliOptions.s3SnapshotBucket ?? hubConfig.s3SnapshotBucket,
hubOperatorFid: parseInt(cliOptions.hubOperatorFid ?? hubConfig.hubOperatorFid),
};

// Startup check for Hub Operator FID
if (options.hubOperatorFid && !isNaN(options.hubOperatorFid)) {
try {
const fid = options.hubOperatorFid;
const response = await axios.get(`https://fnames.farcaster.xyz/transfers?fid=${fid}`);
const transfers = response.data.transfers;
if (transfers && transfers.length > 0) {
const usernameField = transfers[transfers.length - 1].username;
if (usernameField !== null && usernameField !== undefined) {
startupCheck.printStartupCheckStatus(StartupCheckStatus.OK, `Hub Operator FID is ${fid}(${usernameField})`);
} else {
startupCheck.printStartupCheckStatus(
StartupCheckStatus.WARNING,
`Hub Operator FID is ${fid}, but no username was found`,
);
}
}
} catch (e) {
logger.error(e, `Error fetching username for Hub Operator FID ${options.hubOperatorFid}`);
startupCheck.printStartupCheckStatus(
StartupCheckStatus.WARNING,
`Hub Operator FID is ${options.hubOperatorFid}, but no username was found`,
);
}
} else {
startupCheck.printStartupCheckStatus(
StartupCheckStatus.WARNING,
"Hub Operator FID is not set",
"https://www.thehubble.xyz/intro/install.html#troubleshooting",
);
}

if (options.enableSnapshotToS3) {
// Set the Hub to exit (and be automatically restarted) so that the snapshot is uploaded
// before the Hub starts syncing
Expand Down
9 changes: 9 additions & 0 deletions apps/hubble/src/hubble.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ export const FARCASTER_VERSIONS_SCHEDULE: VersionSchedule[] = [

export interface HubInterface {
engine: Engine;
identity: string;
hubOperatorFid?: number;
submitMessage(message: Message, source?: HubSubmitSource): HubAsyncResult<number>;
submitIdRegistryEvent(event: IdRegistryEvent, source?: HubSubmitSource): HubAsyncResult<number>;
submitNameRegistryEvent(event: NameRegistryEvent, source?: HubSubmitSource): HubAsyncResult<number>;
Expand Down Expand Up @@ -262,6 +264,9 @@ export interface HubOptions {

/** S3 bucket to upload snapshots to */
s3SnapshotBucket?: string;

/** Hub Operator's FID */
hubOperatorFid?: number;
}

/** @returns A randomized string of the format `rocksdb.tmp.*` used for the DB Name */
Expand Down Expand Up @@ -434,6 +439,10 @@ export class Hub implements HubInterface {
return this.gossipNode.multiaddrs ?? [];
}

get hubOperatorFid() {
return this.options.hubOperatorFid ?? 0;
}

/** Returns the Gossip peerId string of this Hub */
get identity(): string {
if (!this.gossipNode.isStarted() || !this.gossipNode.peerId) {
Expand Down
5 changes: 4 additions & 1 deletion apps/hubble/src/network/sync/syncEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,12 +393,14 @@ class SyncEngine extends TypedEmitter<SyncEvents> {
}

try {
// First, get the latest state from the peer
// First, get the latest state and info from the peer
const peerStateResult = await rpcClient.getSyncSnapshotByPrefix(
TrieNodePrefix.create({ prefix: new Uint8Array() }),
new Metadata(),
rpcDeadline(),
);
const peerInfo = await rpcClient.getInfo({ dbStats: false }, new Metadata(), rpcDeadline());

if (peerStateResult.isErr()) {
log.warn(
{ error: peerStateResult.error, errMsg: peerStateResult.error.message, peerId, peerContact },
Expand Down Expand Up @@ -429,6 +431,7 @@ class SyncEngine extends TypedEmitter<SyncEvents> {
log.info(
{
peerId,
hubOperatorFid: peerInfo.map((info) => info.hubOperatorFid).unwrapOr(0),
inSync: syncStatus.inSync,
isSyncing: syncStatus.isSyncing,
theirMessages: syncStatus.theirSnapshot.numMessages,
Expand Down
5 changes: 5 additions & 0 deletions apps/hubble/src/rpc/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,11 @@ export default class Server {
isSyncing: !this.syncEngine?.isSyncing(),
nickname: APP_NICKNAME,
rootHash: (await this.syncEngine?.trie.rootHash()) ?? "",
peerId: Result.fromThrowable(
() => this.hub?.identity ?? "",
(e) => e,
)().unwrapOr(""),
hubOperatorFid: this.hub?.hubOperatorFid ?? 0,
});

if (call.request.dbStats && this.syncEngine) {
Expand Down
10 changes: 5 additions & 5 deletions apps/hubble/src/storage/engine/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,11 @@ class Engine {
}

async mergeMessage(message: Message): HubAsyncResult<number> {
const validatedMessage = await this.validateMessage(message);
if (validatedMessage.isErr()) {
return err(validatedMessage.error);
}

// Extract the FID that this message was signed by
const fid = message.data?.fid ?? 0;
const storageUnits = await this.eventHandler.getCurrentStorageUnitsForFid(fid);
Expand All @@ -259,11 +264,6 @@ class Engine {
}
}

const validatedMessage = await this.validateMessage(message);
if (validatedMessage.isErr()) {
return err(validatedMessage.error);
}

// rome-ignore lint/style/noNonNullAssertion: legacy code, avoid using ignore for new code
const setPostfix = typeToSetPostfix(message.data!.type);

Expand Down
3 changes: 3 additions & 0 deletions apps/hubble/src/test/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export class MockHub implements HubInterface {
this.gossipNode = gossipNode;
}

identity = "mock";
hubOperatorFid = 0;

async submitMessage(message: Message, source?: HubSubmitSource): HubAsyncResult<number> {
const result = await this.engine.mergeMessage(message);

Expand Down
11 changes: 10 additions & 1 deletion apps/hubble/www/docs/docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Start a Hub
Hubble Options:
-n --network <network> ID of the Farcaster Network (default: 3 (devnet))
-i, --id <filepath> Path to the PeerId file.
--hub-operator-fid The FID of the hub operator. Optional.
--hub-operator-fid <fid> The FID of the hub operator. Optional.
-c, --config <filepath> Path to the config file.
--db-name <name> The name of the RocksDB instance. (default: rocks.hub._default)
--admin-server-enabled Enable the admin server. (default: disabled)
Expand Down Expand Up @@ -57,6 +57,7 @@ Snapshots Options:
--enable-snapshot-to-s3 Enable daily snapshots to be uploaded to S3. (default: disabled)
--s3-snapshot-bucket <bucket> The S3 bucket to upload snapshots to
--disable-snapshot-sync Disable syncing from snapshots. (default: enabled)
Metrics:
--statsd-metrics-server <host> The host to send statsd metrics to, eg "127.0.0.1:8125". (default: disabled)
Expand All @@ -72,6 +73,14 @@ Networking Options:
--denied-peers <peerIds...> Do not peer with specific peer ids. (default: no peers denied)
--rpc-rate-limit <number> RPC rate limit for peers specified in rpm. Set to -1 for none. (default: 20k/min)
Snapshots Options:
--enable-snapshot-to-s3 Enable daily snapshots to be uploaded to S3. (default: disabled)
--s3-snapshot-bucket <bucket> The S3 bucket to upload snapshots to
--disable-snapshot-sync Disable syncing from snapshots. (default: enabled)
Metrics:
--statsd-metrics-server <host> The host to send statsd metrics to, eg "127.0.0.1:8125". (default: disabled)
Debugging Options:
--gossip-metrics-enabled Generate tracing and metrics for the gossip network. (default: disabled)
--profile-sync Profile a full hub sync and exit. (default: disabled)
Expand Down
8 changes: 7 additions & 1 deletion apps/hubble/www/docs/intro/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ ETH_MAINNET_RPC_URL=your-ETH-mainnet-RPC-URL

# Set this to your L2 Optimism Mainnet RPC URL
OPTIMISM_L2_RPC_URL=your-L2-optimism-RPC-URL

HUB_OPERATOR_FID=your-fid
```

5. Follow the instructions to set [connect to a network](./networks.md).
Expand Down Expand Up @@ -111,7 +113,7 @@ To run the Hubble commands, go to the Hubble app (`cd apps/hubble`) and run the

1. `yarn identity create` to create a ID
2. Follow the instructions to set [connect to a network](./networks.md)
3. `yarn start --eth-mainnet-rpc-url <your ETH-mainnet-RPC-URL> --l2-rpc-url <your Optimism-L2-RPC-URL>`
3. `yarn start --eth-mainnet-rpc-url <your ETH-mainnet-RPC-URL> --l2-rpc-url <your Optimism-L2-RPC-URL> --hub-operator-fid <your FID>`

### Upgrading Hubble

Expand Down Expand Up @@ -159,3 +161,7 @@ docker pull farcasterxyz/hubble:latest
# Get a specific release (v1.4.0)
docker pull farcasterxyz/hubble@v1.4.0
```

- To set the Hub operator FID
* If you are running via docker or the script, please set this in your `.env` file: `HUB_OPERATOR_FID=your-fid`
* If you are running via source `yarn start --hub-operator-fid <your-fid>`
38 changes: 37 additions & 1 deletion packages/core/src/protobufs/generated/request_response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ export interface HubInfoResponse {
nickname: string;
rootHash: string;
dbStats: DbStats | undefined;
peerId: string;
hubOperatorFid: number;
}

export interface DbStats {
Expand Down Expand Up @@ -529,7 +531,15 @@ export const HubInfoRequest = {
};

function createBaseHubInfoResponse(): HubInfoResponse {
return { version: "", isSyncing: false, nickname: "", rootHash: "", dbStats: undefined };
return {
version: "",
isSyncing: false,
nickname: "",
rootHash: "",
dbStats: undefined,
peerId: "",
hubOperatorFid: 0,
};
}

export const HubInfoResponse = {
Expand All @@ -549,6 +559,12 @@ export const HubInfoResponse = {
if (message.dbStats !== undefined) {
DbStats.encode(message.dbStats, writer.uint32(42).fork()).ldelim();
}
if (message.peerId !== "") {
writer.uint32(50).string(message.peerId);
}
if (message.hubOperatorFid !== 0) {
writer.uint32(56).uint64(message.hubOperatorFid);
}
return writer;
},

Expand Down Expand Up @@ -594,6 +610,20 @@ export const HubInfoResponse = {

message.dbStats = DbStats.decode(reader, reader.uint32());
continue;
case 6:
if (tag != 50) {
break;
}

message.peerId = reader.string();
continue;
case 7:
if (tag != 56) {
break;
}

message.hubOperatorFid = longToNumber(reader.uint64() as Long);
continue;
}
if ((tag & 7) == 4 || tag == 0) {
break;
Expand All @@ -610,6 +640,8 @@ export const HubInfoResponse = {
nickname: isSet(object.nickname) ? String(object.nickname) : "",
rootHash: isSet(object.rootHash) ? String(object.rootHash) : "",
dbStats: isSet(object.dbStats) ? DbStats.fromJSON(object.dbStats) : undefined,
peerId: isSet(object.peerId) ? String(object.peerId) : "",
hubOperatorFid: isSet(object.hubOperatorFid) ? Number(object.hubOperatorFid) : 0,
};
},

Expand All @@ -620,6 +652,8 @@ export const HubInfoResponse = {
message.nickname !== undefined && (obj.nickname = message.nickname);
message.rootHash !== undefined && (obj.rootHash = message.rootHash);
message.dbStats !== undefined && (obj.dbStats = message.dbStats ? DbStats.toJSON(message.dbStats) : undefined);
message.peerId !== undefined && (obj.peerId = message.peerId);
message.hubOperatorFid !== undefined && (obj.hubOperatorFid = Math.round(message.hubOperatorFid));
return obj;
},

Expand All @@ -636,6 +670,8 @@ export const HubInfoResponse = {
message.dbStats = (object.dbStats !== undefined && object.dbStats !== null)
? DbStats.fromPartial(object.dbStats)
: undefined;
message.peerId = object.peerId ?? "";
message.hubOperatorFid = object.hubOperatorFid ?? 0;
return message;
},
};
Expand Down
Loading

0 comments on commit bc416db

Please sign in to comment.