Skip to content

Commit

Permalink
feat: remove GCP storage dependency from SDK (#5000)
Browse files Browse the repository at this point in the history
### Description

- feat: remove GCP storage dependency
- call GCP storage API directly

### Drive-by changes

- little refactor
- add dec 4 batch sha to the validator version checker

### Related issues

<!--
- Fixes #[issue number here]
-->

### Backward compatibility

<!--
Are these changes backward compatible? Are there any infrastructure
implications, e.g. changes that would prohibit deploying older commits
using this infra tooling?

Yes/No
-->

### Testing

test by checking version of flowmainnet validators, because we know the
flow foundation validator is on GCP storage
https://evm.flowscan.io/tx/0x4ac998b0d35b3d305e792ee608818a398d09ee11851e09e37068f67ce8c6153f?tab=logs
```
# from repo root
yarn --cwd typescript/infra tsx scripts/check/check-validator-version.ts -e mainnet3 -c flowmainnet --show-updated
```
```
✅ 4 Validators with expected git SHA:
┌─────────┬───────────────┬──────────────────────────────────────────────┬───────────────────┬───────────────┐
│ (index) │ chain         │ validator                                    │ alias             │ version       │
├─────────┼───────────────┼──────────────────────────────────────────────┼───────────────────┼───────────────┤
│ 0       │ 'flowmainnet' │ '0xe132235c958ca1f3f24d772e5970dd58da4c0f6e' │ 'Abacus Works'    │ 'nov-7-batch' │
│ 1       │ 'flowmainnet' │ '0x14ADB9e3598c395Fe3290f3ba706C3816Aa78F59' │ 'Flow Foundation' │ 'nov-7-batch' │
│ 2       │ 'flowmainnet' │ '0xcf0211fafbb91fd9d06d7e306b30032dc3a1934f' │ 'Merkly'          │ 'nov-7-batch' │
│ 3       │ 'flowmainnet' │ '0x4f977a59fdc2d9e39f6d780a84d5b4add1495a36' │ 'Mitosis'         │ 'dec-4-batch' │
└─────────┴───────────────┴──────────────────────────────────────────────┴───────────────────┴───────────────┘

✅ All validators running expected git SHA!
```
  • Loading branch information
paulbalaji authored Dec 13, 2024
1 parent 7ceb81d commit 82cebab
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 131 deletions.
5 changes: 5 additions & 0 deletions .changeset/many-clouds-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/sdk': minor
---

Call google storage API directly and remove @google-cloud/storage dependency from the SDK.
2 changes: 2 additions & 0 deletions typescript/infra/scripts/check/check-validator-version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const acceptableValidatorVersions: Record<string, string> = {
'd834d8147628584acd78a81e344bff76472d707e': 'nov-21-bsquared',
// Nov 21 swell/lumiaprism deploy
'b35c105f197267072daa14bb3d83c62410b96fac': 'nov-21-swell',
// Dec 4 deploy
'a7f3967e047c2c5aabb8cc442e4acad435fa32ab': 'dec-4-batch',
// Rolled out only to AW infra before 1.0.0, just 1 commit behind 1.0.0
'a64af8be9a76120d0cfc727bb70660fa07e70cce': 'pre-1.0.0',
// 1.0.0
Expand Down
1 change: 0 additions & 1 deletion typescript/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
"@chain-registry/types": "^0.50.14",
"@cosmjs/cosmwasm-stargate": "^0.32.4",
"@cosmjs/stargate": "^0.32.4",
"@google-cloud/storage": "7.14.0",
"@hyperlane-xyz/core": "5.8.3",
"@hyperlane-xyz/utils": "7.3.0",
"@safe-global/api-kit": "1.3.0",
Expand Down
81 changes: 54 additions & 27 deletions typescript/sdk/src/gcp/storage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Storage } from '@google-cloud/storage';

export const GCS_BUCKET_REGEX =
/^(?:(?:https?:\/\/)?([^/]+)\.storage\.googleapis\.com\/?|gs:\/\/([^/]+))$/;

Expand All @@ -18,66 +16,95 @@ export interface StorageConfig {
}

export class GcpStorageWrapper {
private readonly client: Storage;
private readonly bucket: string;
private cache: Record<string, StorageReceipt<any>> | undefined;
private readonly baseUrl: string;

static fromBucketUrl(bucketUrl: string): GcpStorageWrapper {
const match = bucketUrl.match(GCS_BUCKET_REGEX);
if (!match) throw new Error('Could not parse bucket url');
return new GcpStorageWrapper({
bucket: match[1],
// Handle both http and gs:// formats
bucket: match[1] || match[2],
caching: true,
});
}

constructor(readonly config: StorageConfig) {
this.client = new Storage({
projectId: config.projectId,
keyFilename: config.keyFilename,
});
this.bucket = config.bucket;
this.baseUrl = `https://storage.googleapis.com/storage/v1/b/${this.bucket}/o`;
if (config.caching) {
this.cache = {};
}
}

formatKey(key: string): string {
private formatKey(key: string): string {
return this.config.folder ? `${this.config.folder}/${key}` : key;
}

async getObject<T>(key: string): Promise<StorageReceipt<T> | undefined> {
const Key = this.formatKey(key);
if (this.cache?.[Key]) {
return this.cache![Key];
private getCachedObject<T>(key: string): StorageReceipt<T> | undefined {
return this.cache?.[key];
}

private setCachedObject<T>(key: string, value: StorageReceipt<T>): void {
if (this.cache) {
this.cache[key] = value;
}
}

try {
const bucket = this.client.bucket(this.bucket);
const file = bucket.file(Key);
const [exists] = await file.exists();
private async fetchMetadata(key: string): Promise<any> {
const url = new URL(`${this.baseUrl}/${encodeURIComponent(key)}`);
const response = await fetch(url.toString());

if (!exists) {
return undefined;
}
if (response.status === 404) return undefined;

if (!response.ok) {
const responseText = await response.text();
throw new Error(
`Failed to fetch object metadata: ${response.statusText}. ${responseText}`,
);
}

return response.json();
}

private async fetchContent(key: string): Promise<string> {
const url = `${this.baseUrl}/${encodeURIComponent(key)}?alt=media`;
const response = await fetch(url);
const responseText = await response.text();

if (!response.ok) {
throw new Error(
`Failed to fetch object content: ${response.statusText}. ${responseText}`,
);
}

return responseText;
}

const [metadata] = await file.getMetadata();
const [contents] = await file.download();
const body = contents.toString('utf-8');
async getObject<T>(key: string): Promise<StorageReceipt<T> | undefined> {
const formattedKey = this.formatKey(key);
const cachedObject = this.getCachedObject<T>(formattedKey);
if (cachedObject) {
return cachedObject;
}

try {
const metadata = await this.fetchMetadata(formattedKey);
if (!metadata) return undefined;

const body = await this.fetchContent(formattedKey);
const result = {
data: JSON.parse(body),
// If no updated date is provided, use the Unix epoch start
// 0 = Unix epoch start (1970-01-01T00:00:00.000Z)
modified: new Date(metadata.updated ?? 0),
};

if (this.cache) {
this.cache[Key] = result;
}
this.setCachedObject(formattedKey, result);
return result;
} catch (e: any) {
if (e.code === 404) {
if (e.status === 404) {
return undefined;
}
throw e;
Expand Down
106 changes: 3 additions & 103 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7205,30 +7205,6 @@ __metadata:
languageName: node
linkType: hard

"@google-cloud/paginator@npm:^5.0.0":
version: 5.0.2
resolution: "@google-cloud/paginator@npm:5.0.2"
dependencies:
arrify: "npm:^2.0.0"
extend: "npm:^3.0.2"
checksum: 10/b64ba2029b77fdcf3c827aea0b6d128122fd1d2f4aa8c1ba70747cba0659d4216a283769fb3bbeb8f726176f5282624637f02c30f118a010e05838411da0cb76
languageName: node
linkType: hard

"@google-cloud/projectify@npm:^4.0.0":
version: 4.0.0
resolution: "@google-cloud/projectify@npm:4.0.0"
checksum: 10/fdccdda0b50855c35541d71c46a6603f3302ff1a00108d946272cb2167435da00e2a2da5963fe489f4f5a4a9eb6320abeb97d3269974a972ae89f5df8451922d
languageName: node
linkType: hard

"@google-cloud/promisify@npm:^4.0.0":
version: 4.0.0
resolution: "@google-cloud/promisify@npm:4.0.0"
checksum: 10/c5de81321b3a5c567edcbe0b941fb32644611147f3ba22f20575918c225a979988a99bc2ebda05ac914fa8714b0a54c69be72c3f46c7a64c3b19db7d7fba8d04
languageName: node
linkType: hard

"@google-cloud/secret-manager@npm:^5.5.0":
version: 5.5.0
resolution: "@google-cloud/secret-manager@npm:5.5.0"
Expand All @@ -7238,29 +7214,6 @@ __metadata:
languageName: node
linkType: hard

"@google-cloud/storage@npm:7.14.0":
version: 7.14.0
resolution: "@google-cloud/storage@npm:7.14.0"
dependencies:
"@google-cloud/paginator": "npm:^5.0.0"
"@google-cloud/projectify": "npm:^4.0.0"
"@google-cloud/promisify": "npm:^4.0.0"
abort-controller: "npm:^3.0.0"
async-retry: "npm:^1.3.3"
duplexify: "npm:^4.1.3"
fast-xml-parser: "npm:^4.4.1"
gaxios: "npm:^6.0.2"
google-auth-library: "npm:^9.6.3"
html-entities: "npm:^2.5.2"
mime: "npm:^3.0.0"
p-limit: "npm:^3.0.1"
retry-request: "npm:^7.0.0"
teeny-request: "npm:^9.0.0"
uuid: "npm:^8.0.0"
checksum: 10/0726fde2697da696637fab91ebd756354a58c1331f6a0b9ecc5011de4aae72cd9e1fe3e9564aee15c6a2118e45ed0ae8c3ac9685c6581db6107080f906a949e9
languageName: node
linkType: hard

"@grpc/grpc-js@npm:~1.10.3":
version: 1.10.8
resolution: "@grpc/grpc-js@npm:1.10.8"
Expand Down Expand Up @@ -7602,7 +7555,6 @@ __metadata:
"@cosmjs/cosmwasm-stargate": "npm:^0.32.4"
"@cosmjs/stargate": "npm:^0.32.4"
"@eslint/js": "npm:^9.15.0"
"@google-cloud/storage": "npm:7.14.0"
"@hyperlane-xyz/core": "npm:5.8.3"
"@hyperlane-xyz/utils": "npm:7.3.0"
"@nomiclabs/hardhat-ethers": "npm:^2.2.3"
Expand Down Expand Up @@ -17874,13 +17826,6 @@ __metadata:
languageName: node
linkType: hard

"arrify@npm:^2.0.0":
version: 2.0.1
resolution: "arrify@npm:2.0.1"
checksum: 10/067c4c1afd182806a82e4c1cb8acee16ab8b5284fbca1ce29408e6e91281c36bb5b612f6ddfbd40a0f7a7e0c75bf2696eb94c027f6e328d6e9c52465c98e4209
languageName: node
linkType: hard

"as-table@npm:^1.0.36":
version: 1.0.55
resolution: "as-table@npm:1.0.55"
Expand Down Expand Up @@ -21074,7 +21019,7 @@ __metadata:
languageName: node
linkType: hard

"duplexify@npm:^4.0.0, duplexify@npm:^4.1.2, duplexify@npm:^4.1.3":
"duplexify@npm:^4.0.0, duplexify@npm:^4.1.2":
version: 4.1.3
resolution: "duplexify@npm:4.1.3"
dependencies:
Expand Down Expand Up @@ -23202,17 +23147,6 @@ __metadata:
languageName: node
linkType: hard

"fast-xml-parser@npm:^4.4.1":
version: 4.5.0
resolution: "fast-xml-parser@npm:4.5.0"
dependencies:
strnum: "npm:^1.0.5"
bin:
fxparser: src/cli/cli.js
checksum: 10/dc9571c10e7b57b5be54bcd2d92f50c446eb42ea5df347d253e94dd14eb99b5300a6d172e840f151e0721933ca2406165a8d9b316a6d777bf0596dc4fe1df756
languageName: node
linkType: hard

"fastq@npm:^1.6.0":
version: 1.13.0
resolution: "fastq@npm:1.13.0"
Expand Down Expand Up @@ -23955,19 +23889,6 @@ __metadata:
languageName: node
linkType: hard

"gaxios@npm:^6.0.2":
version: 6.7.1
resolution: "gaxios@npm:6.7.1"
dependencies:
extend: "npm:^3.0.2"
https-proxy-agent: "npm:^7.0.1"
is-stream: "npm:^2.0.0"
node-fetch: "npm:^2.6.9"
uuid: "npm:^9.0.1"
checksum: 10/c85599162208884eadee91215ebbfa1faa412551df4044626cb561300e15193726e8f23d63b486533e066dadad130f58ed872a23acab455238d8d48b531a0695
languageName: node
linkType: hard

"gcp-metadata@npm:^6.1.0":
version: 6.1.0
resolution: "gcp-metadata@npm:6.1.0"
Expand Down Expand Up @@ -24475,20 +24396,6 @@ __metadata:
languageName: node
linkType: hard

"google-auth-library@npm:^9.6.3":
version: 9.15.0
resolution: "google-auth-library@npm:9.15.0"
dependencies:
base64-js: "npm:^1.3.0"
ecdsa-sig-formatter: "npm:^1.0.11"
gaxios: "npm:^6.1.1"
gcp-metadata: "npm:^6.1.0"
gtoken: "npm:^7.0.0"
jws: "npm:^4.0.0"
checksum: 10/fba2db9732bbf1b3a3a2e2b45131ba8e8aba297377f1c104d0b2ab3386bbc1e02047f20b8a7afca1c6308492da1540104618f1c7b5cd539703552e10399c560e
languageName: node
linkType: hard

"google-gax@npm:^4.0.3":
version: 4.3.3
resolution: "google-gax@npm:4.3.3"
Expand Down Expand Up @@ -25170,13 +25077,6 @@ __metadata:
languageName: node
linkType: hard

"html-entities@npm:^2.5.2":
version: 2.5.2
resolution: "html-entities@npm:2.5.2"
checksum: 10/4ec12ebdf2d5ba8192c68e1aef3c1e4a4f36b29246a0a88464fe278a54517d0196d3489af46a3145c7ecacb4fc5fd50497be19eb713b810acab3f0efcf36fdc2
languageName: node
linkType: hard

"html-escaper@npm:^2.0.0":
version: 2.0.2
resolution: "html-escaper@npm:2.0.2"
Expand Down Expand Up @@ -30113,7 +30013,7 @@ __metadata:
languageName: node
linkType: hard

"p-limit@npm:^3.0.1, p-limit@npm:^3.0.2, p-limit@npm:^3.1.0":
"p-limit@npm:^3.0.2, p-limit@npm:^3.1.0":
version: 3.1.0
resolution: "p-limit@npm:3.1.0"
dependencies:
Expand Down Expand Up @@ -36411,7 +36311,7 @@ __metadata:
languageName: node
linkType: hard

"uuid@npm:^8.0.0, uuid@npm:^8.3.2":
"uuid@npm:^8.3.2":
version: 8.3.2
resolution: "uuid@npm:8.3.2"
bin:
Expand Down

0 comments on commit 82cebab

Please sign in to comment.