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

feature: store asset fingerprint #437

Merged
merged 1 commit into from
Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
Binary file added packages-cache/@emurgo-cip14-js-2.0.0.tgz
Binary file not shown.
Binary file added packages-cache/bech32-2.0.0.tgz
Binary file not shown.
Binary file added packages-cache/blake2b-2.1.3.tgz
Binary file not shown.
Binary file added packages-cache/blake2b-wasm-1.1.7.tgz
Binary file not shown.
Binary file added packages-cache/nanoassert-1.1.0.tgz
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
- assetId
- assetName
- description
- fingerprint
- logo
- metadataFetchAttempts
- metadataHash
Expand All @@ -70,6 +71,7 @@
- assetId
- assetName
- description
- fingerprint
- logo
- metadataFetchAttempts
- metadataHash
Expand All @@ -88,6 +90,7 @@
- assetId
- assetName
- description
- fingerprint
- logo
- metadataFetchAttempts
- metadataHash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ CREATE TABLE IF NOT EXISTS "Asset"
SELECT
DISTINCT CONCAT(RIGHT(CONCAT(E'\\', policy), -3), RIGHT(CONCAT(E'\\', name), -3)) as "assetId",
CAST(NULL AS TEXT) AS "ticker",
name as "assetName",
RIGHT(CONCAT(E'\\', name), -3) as "assetName",
CAST(NULL AS TEXT) AS "description",
CAST(NULL AS CHAR(44)) as "fingerprint",
CAST(NULL AS TEXT) AS "logo",
0 AS "metadataFetchAttempts",
CAST(NULL AS CHAR(40)) AS "metadataHash",
Expand Down
11 changes: 11 additions & 0 deletions packages/api-cardano-db-hasura/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ schema {
query: Query
}

scalar AssetFingerprint
scalar BigInt
scalar DateTime
scalar Hash28Hex
Expand Down Expand Up @@ -248,6 +249,7 @@ type Asset {
assetId: String!
assetName: String
description: String
fingerprint: AssetFingerprint
logo: String
metadataHash: String
name: String
Expand All @@ -264,6 +266,7 @@ input Asset_bool_exp {
assetId: text_comparison_exp
assetName: text_comparison_exp
description: text_comparison_exp
fingerprint: AssetFingerprint_comparison_exp
logo: text_comparison_exp
name: text_comparison_exp
policyId: text_comparison_exp
Expand All @@ -273,6 +276,7 @@ input Asset_bool_exp {

input Asset_order_by {
assetId: order_by
fingerprint: order_by
name: order_by
}

Expand Down Expand Up @@ -1402,6 +1406,13 @@ input text_comparison_exp {
_similar: String
}

input AssetFingerprint_comparison_exp {
_eq: String
_in: [String]
_neq: String
_nin: [String]
}

# ordering options
enum order_by {
# in the ascending order, nulls last
Expand Down
21 changes: 20 additions & 1 deletion packages/api-cardano-db-hasura/src/DataSyncController.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import axios, { AxiosInstance } from 'axios'
import { chunkArray, DataFetcher } from '@cardano-graphql/util'
import AssetFingerprint from '@emurgo/cip14-js'
import { Asset } from './graphql_types'
import hash from 'object-hash'
import { dummyLogger, Logger } from 'ts-log'
Expand All @@ -11,6 +12,12 @@ export interface Signature {
publicKey: string
}

export const assetFingerprint = (asset: Pick<Asset, 'assetName' | 'policyId'>) =>
new AssetFingerprint(
Buffer.from(asset.policyId, 'hex'),
asset.assetName !== '' ? Buffer.from(asset.assetName, 'hex') : undefined)
.fingerprint()

export interface AssetMetadata {
ticker: {
value: string
Expand Down Expand Up @@ -108,6 +115,7 @@ export class DataSyncController {
.map(asset => ({
assetId: asset.assetId,
assetName: asset.assetName,
fingerprint: assetFingerprint(asset),
policyId: asset.policyId,
metadataFetchAttempts: 0
})
Expand Down Expand Up @@ -153,10 +161,10 @@ export class DataSyncController {
const response = await this.axiosClient.post('query', {
subjects: assets.map(asset => asset.assetId),
properties: [
'ticker',
'description',
'logo',
'name',
'ticker',
'unit',
'url'
]
Expand All @@ -168,8 +176,19 @@ export class DataSyncController {
}
}

private async ensureAssetFingerprints (): Promise<void> {
const assets = await this.hasuraClient.getAssetsWithoutFingerprint()
this.logger.debug('Assets without fingerprint', { module: 'DataSyncController', value: assets.length })
for (const asset of assets) {
const fingerprint = assetFingerprint(asset)
this.logger.debug('Asset', { module: 'DataSyncController', value: { assetId: asset.assetId, fingerprint } })
await this.hasuraClient.addAssetFingerprint(asset.assetId, fingerprint)
}
}

public async initialize () {
this.logger.info('Initializing', { module: 'DataSyncController' })
await this.ensureAssetFingerprints()
await this.assetSynchronizer.initialize()
if (this.metadataServerUri) {
await this.metadataSynchronizer.initial.initialize()
Expand Down
45 changes: 44 additions & 1 deletion packages/api-cardano-db-hasura/src/HasuraClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,22 @@ export class HasuraClient {
return result.data.assets
}

public async getAssetsWithoutFingerprint (): Promise<Pick<Asset, 'assetId' | 'assetName' | 'policyId'>[]> {
const result = await this.client.query({
query: gql`query {
assets (where: { fingerprint: { _is_null: true }}) {
assetId
assetName
policyId
}
}`
})
return result.data.assets.map((asset: Asset) => ({
...asset,
policyId: util.scalars.Hash28Hex.serialize(asset.policyId)
}))
}

public async getAssetsWithoutMetadata (metadataFetchAttempts: IntComparisonExp): Promise<Asset[]> {
const result = await this.client.query({
query: gql`query IdsOfAssetsWithoutMetadata (
Expand All @@ -353,8 +369,35 @@ export class HasuraClient {
return result.data.assets
}

public addAssetFingerprint (assetId: Asset['assetId'], fingerprint: Asset['fingerprint']) {
this.logger.debug('adding fingerprint to asset', { module: 'HasuraClient', value: { assetId, fingerprint } })
return this.client.mutate({
mutation: gql`mutation AddAssetFingerprint(
$assetId: String!
$fingerprint: bpchar!
) {
update_assets(
where: {
assetId: { _eq: $assetId }
},
_set: {
fingerprint: $fingerprint,
}
) {
returning {
assetId
}
}
}`,
variables: {
assetId,
fingerprint
}
})
}

public addMetadata (metadata: AssetMetadata, metadataHash: string) {
this.logger.info('adding metadata to asset', { module: 'HasuraClient', value: { assetId: metadata.subject, metadataHash } })
this.logger.debug('adding metadata to asset', { module: 'HasuraClient', value: { assetId: metadata.subject, metadataHash } })
return this.client.mutate({
mutation: gql`mutation AddAssetMetadata(
$ticker: String
Expand Down
1 change: 1 addition & 0 deletions packages/api-cardano-db-hasura/src/executableSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { CardanoNodeClient } from './CardanoNodeClient'
const GraphQLBigInt = require('graphql-bigint')

export const scalarResolvers = {
AssetFingerprint: util.scalars.AssetFingerprint,
BigInt: GraphQLBigInt,
DateTime: util.scalars.DateTimeUtcToIso,
Hash28Hex: util.scalars.Hash28Hex,
Expand Down
1 change: 1 addition & 0 deletions packages/util/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
},
"homepage": "https://github.com/input-output-hk/cardano-graphql/blob/master/packages/util/README.md",
"dependencies": {
"@emurgo/cip14-js": "^2.0.0",
"dayjs": "^1.8.29",
"graphql": "14.5.8",
"graphql-bigint": "^1.0.0",
Expand Down
26 changes: 26 additions & 0 deletions packages/util/src/scalars/AssetFingerprint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { GraphQLError, GraphQLScalarType, Kind } from 'graphql'

export const AssetFingerprint = new GraphQLScalarType({
name: 'AssetFingerprint',
description: 'CIP14 User-facing asset fingerprint as a bech32-encoded blake2b-160 digest of the concatenation of policy id and asset name.',
serialize (value: string) {
return value
},
parseValue (value: string) {
return validateInput(value)
},
parseLiteral (ast) {
switch (ast.kind) {
case Kind.STRING :
return validateInput(ast.value)
}
}
})

function validateInput (input: string) {
if (
input.length !== 44 &&
input.substr(0, 5) !== 'asset'
) throw new GraphQLError(`${input} is not a valid AssetFingerprint`)
return input
}
1 change: 1 addition & 0 deletions packages/util/src/scalars/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './AssetFingerprint'
export * from './DateTimeUtcToIso'
export * from './Hash28Hex'
export * from './Hash32Hex'
Expand Down
33 changes: 33 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,14 @@
resolved "https://registry.yarnpkg.com/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-6.0.0.tgz#6496fbe34e5ac0af522ed0fe6919c34bedb00283"
integrity sha512-8PaFFGqd2hD0KcSMcFh2f6VZx3G6wpzl4KhwiwyuEhUd+NWYT5ITQNFBmST0pJ6yQPP99/6Z3nc1L1dk60fGGA==

"@emurgo/cip14-js@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@emurgo/cip14-js/-/cip14-js-2.0.0.tgz#6ef78ddac8a35f2725e9ccebfd5ae114716c4b48"
integrity sha512-EvjgTs4NCqH1j0wxXqWCj31P7NmTzl3aR+9am0OLSsf3NA9GsdKH5QNyXJrvSZILM4yWzlZNum3y8S5PfdM1aA==
dependencies:
bech32 "2.0.0"
blake2b "2.1.3"

"@graphql-codegen/cli@^1.15.2":
version "1.16.2"
resolved "https://registry.yarnpkg.com/@graphql-codegen/cli/-/cli-1.16.2.tgz#ff92e5e6813a404616d7504500be26ff88b7092d"
Expand Down Expand Up @@ -2674,6 +2682,11 @@ bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2:
dependencies:
tweetnacl "^0.14.3"

bech32@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/bech32/-/bech32-2.0.0.tgz#078d3686535075c8c79709f054b1b226a133b355"
integrity sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==

bignumber.js@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075"
Expand Down Expand Up @@ -2711,6 +2724,21 @@ bl@^4.0.1:
inherits "^2.0.4"
readable-stream "^3.4.0"

blake2b-wasm@^1.1.0:
version "1.1.7"
resolved "https://registry.yarnpkg.com/blake2b-wasm/-/blake2b-wasm-1.1.7.tgz#e4d075da10068e5d4c3ec1fb9accc4d186c55d81"
integrity sha512-oFIHvXhlz/DUgF0kq5B1CqxIDjIJwh9iDeUUGQUcvgiGz7Wdw03McEO7CfLBy7QKGdsydcMCgO9jFNBAFCtFcA==
dependencies:
nanoassert "^1.0.0"

blake2b@2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/blake2b/-/blake2b-2.1.3.tgz#f5388be424768e7c6327025dad0c3c6d83351bca"
integrity sha512-pkDss4xFVbMb4270aCyGD3qLv92314Et+FsKzilCLxDz5DuZ2/1g3w4nmBbu6nKApPspnjG7JcwTjGZnduB1yg==
dependencies:
blake2b-wasm "^1.1.0"
nanoassert "^1.0.0"

blessed@0.1.81:
version "0.1.81"
resolved "https://registry.yarnpkg.com/blessed/-/blessed-0.1.81.tgz#f962d687ec2c369570ae71af843256e6d0ca1129"
Expand Down Expand Up @@ -6570,6 +6598,11 @@ nan@^2.14.0:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==

nanoassert@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-1.1.0.tgz#4f3152e09540fde28c76f44b19bbcd1d5a42478d"
integrity sha1-TzFS4JVA/eKMdvRLGbvNHVpCR40=

nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
Expand Down