Skip to content

Commit

Permalink
Merge pull request #161 from ckb-cell/develop (release v2.3.0)
Browse files Browse the repository at this point in the history
Merge develop to main branch (release v2.3.0)
  • Loading branch information
Flouse authored Jun 5, 2024
2 parents 2f8f7ee + 6991c24 commit aa1f43e
Show file tree
Hide file tree
Showing 29 changed files with 2,952 additions and 553 deletions.
2 changes: 1 addition & 1 deletion devbox.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"packages": [
"nodejs@latest",
"nodejs@20",
"nodePackages.pnpm@latest",
"redis@latest"
]
Expand Down
87 changes: 66 additions & 21 deletions devbox.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,108 @@
"lockfile_version": "1",
"packages": {
"nodePackages.pnpm@latest": {
"last_modified": "2024-03-08T13:51:52Z",
"resolved": "github:NixOS/nixpkgs/a343533bccc62400e8a9560423486a3b6c11a23b#nodePackages.pnpm",
"last_modified": "2024-05-22T06:18:38Z",
"resolved": "github:NixOS/nixpkgs/3f316d2a50699a78afe5e77ca486ad553169061e#nodePackages.pnpm",
"source": "devbox-search",
"version": "8.15.3",
"version": "8.15.5",
"systems": {
"aarch64-darwin": {
"store_path": "/nix/store/m9p6q42njy1k33fdzf2axqyhy8vh4vn5-pnpm-8.15.3"
"store_path": "/nix/store/98b2ljlansqmkpkd5pqfgwhcwr5kvsha-pnpm-8.15.5"
},
"aarch64-linux": {
"store_path": "/nix/store/war7jm6ka7afc2v8a78hlq8v9m4pg38m-pnpm-8.15.3"
"store_path": "/nix/store/b0h4xyqwdk2zhyhw42bprjnj2i518sxn-pnpm-8.15.5"
},
"x86_64-darwin": {
"store_path": "/nix/store/3w3bs2cdqx7sivcldcf6drwrhilv511m-pnpm-8.15.3"
"store_path": "/nix/store/7xyc072k4g6430vijvylidqacjxy5dbb-pnpm-8.15.5"
},
"x86_64-linux": {
"store_path": "/nix/store/hcq09j80njlfghy65qmwhn5nq20nk8kl-pnpm-8.15.3"
"store_path": "/nix/store/77wblnm5dnmgnan3695j3mk4r7j75s5j-pnpm-8.15.5"
}
}
},
"nodejs@latest": {
"last_modified": "2024-03-09T07:11:56Z",
"resolved": "github:NixOS/nixpkgs/0e7f98a5f30166cbed344569426850b21e4091d4#nodejs_21",
"nodejs@20": {
"last_modified": "2024-05-22T06:18:38Z",
"plugin_version": "0.0.2",
"resolved": "github:NixOS/nixpkgs/3f316d2a50699a78afe5e77ca486ad553169061e#nodejs_20",
"source": "devbox-search",
"version": "21.7.1",
"version": "20.12.2",
"systems": {
"aarch64-darwin": {
"store_path": "/nix/store/mh1db6rni4mlcr473sh3fy6jg2m38jvg-nodejs-21.7.1"
"outputs": [
{
"name": "out",
"path": "/nix/store/bzzs4kvjyvjjhs3rj08vqpvvzmfggvbv-nodejs-20.12.2",
"default": true
},
{
"name": "libv8",
"path": "/nix/store/c56874bxzncqwy58kif6wfnzy017v1sl-nodejs-20.12.2-libv8"
}
],
"store_path": "/nix/store/bzzs4kvjyvjjhs3rj08vqpvvzmfggvbv-nodejs-20.12.2"
},
"aarch64-linux": {
"store_path": "/nix/store/ziyb3ny5f9hcwp0lsb9gwdv1pqsn03x1-nodejs-21.7.1"
"outputs": [
{
"name": "out",
"path": "/nix/store/y50zafzgnnkrj4hvmk23icv2ggvys8r9-nodejs-20.12.2",
"default": true
},
{
"name": "libv8",
"path": "/nix/store/vc7y8h3c8pwbh4zbvjcyfqrd3fhdjhw6-nodejs-20.12.2-libv8"
}
],
"store_path": "/nix/store/y50zafzgnnkrj4hvmk23icv2ggvys8r9-nodejs-20.12.2"
},
"x86_64-darwin": {
"store_path": "/nix/store/0zaa3aarbsj38g62ihv94gz2hgvgh6bc-nodejs-21.7.1"
"outputs": [
{
"name": "out",
"path": "/nix/store/l53svh1nfrcb83qbqvrrkangrcl1rr25-nodejs-20.12.2",
"default": true
},
{
"name": "libv8",
"path": "/nix/store/q71hh22bfqjygd34gq16dv4dwfc33378-nodejs-20.12.2-libv8"
}
],
"store_path": "/nix/store/l53svh1nfrcb83qbqvrrkangrcl1rr25-nodejs-20.12.2"
},
"x86_64-linux": {
"store_path": "/nix/store/4arhczh30ychpx6h2wpj5nhx39wm0nla-nodejs-21.7.1"
"outputs": [
{
"name": "out",
"path": "/nix/store/6g9n96qf1yx139xklnmy3v4xhjvjgsji-nodejs-20.12.2",
"default": true
},
{
"name": "libv8",
"path": "/nix/store/s7b0dqga0311mvq48mirnlm0p3dr4gm3-nodejs-20.12.2-libv8"
}
],
"store_path": "/nix/store/6g9n96qf1yx139xklnmy3v4xhjvjgsji-nodejs-20.12.2"
}
}
},
"redis@latest": {
"last_modified": "2024-03-08T13:51:52Z",
"last_modified": "2024-05-22T06:18:38Z",
"plugin_version": "0.0.2",
"resolved": "github:NixOS/nixpkgs/a343533bccc62400e8a9560423486a3b6c11a23b#redis",
"resolved": "github:NixOS/nixpkgs/3f316d2a50699a78afe5e77ca486ad553169061e#redis",
"source": "devbox-search",
"version": "7.2.4",
"systems": {
"aarch64-darwin": {
"store_path": "/nix/store/700kyznxcmlkqqabhwa64vmyg4aj6igj-redis-7.2.4"
"store_path": "/nix/store/f1hmasfrq0s1yag27kmdwv97cjxv85rm-redis-7.2.4"
},
"aarch64-linux": {
"store_path": "/nix/store/xlc976dh4nb2aa0gzs0jfgld4cc3x8si-redis-7.2.4"
"store_path": "/nix/store/5ay0vkvk8l2n8fgxnmxdci1y1ldafnx8-redis-7.2.4"
},
"x86_64-darwin": {
"store_path": "/nix/store/5v58fadclljqa2fmwq281bx5wma9cslb-redis-7.2.4"
"store_path": "/nix/store/5l40xjgzqsd56dx5zfwr2v6sfpk12lkl-redis-7.2.4"
},
"x86_64-linux": {
"store_path": "/nix/store/zp1lapdicjxnjhiz8l6j2j4nn6sa9fg5-redis-7.2.4"
"store_path": "/nix/store/xlvzg81dgimxfjxpxwr2w3q1ca3l5lwa-redis-7.2.4"
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "btc-assets-api",
"version": "2.2.1",
"version": "2.3.0",
"title": "Bitcoin/RGB++ Assets API",
"description": "",
"main": "index.js",
Expand Down Expand Up @@ -30,6 +30,7 @@
"@ckb-lumos/ckb-indexer": "^0.22.2",
"@ckb-lumos/codec": "^0.22.2",
"@ckb-lumos/lumos": "0.22.2",
"@ckb-lumos/rpc": "^0.22.2",
"@fastify/compress": "^7.0.0",
"@fastify/cors": "^9.0.1",
"@fastify/http-proxy": "^9.4.0",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions src/plugins/jwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default fp(async (fastify) => {
},
});
fastify.addHook('onRequest', async (request: FastifyRequest, reply: FastifyReply) => {
fastify.Sentry.setTag('request.url', request.url);
if (
request.method.toLowerCase() === 'options' ||
JWT_IGNORE_URLS.some((prefix) => request.url.startsWith(prefix))
Expand All @@ -44,9 +45,11 @@ export default fp(async (fastify) => {
await request.jwtVerify();
const jwt = (await request.jwtDecode()) as JwtPayload;
if (jwt) {
reply.sentryTransaction?.setAttribute('token.id', jwt.jti);
reply.sentryTransaction?.setAttribute('token.app', jwt.sub);
reply.sentryTransaction?.setAttribute('token.domain', jwt.aud);
fastify.Sentry.setTags({
'token.id': jwt.jti,
'token.app': jwt.sub,
'token.domain': jwt.aud,
});
}
if (!jwt.aud) {
reply.status(HttpStatusCode.Unauthorized).send('Invalid audience');
Expand Down
119 changes: 79 additions & 40 deletions src/routes/bitcoin/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,36 +42,58 @@ const addressRoutes: FastifyPluginCallback<Record<never, never>, Server, ZodType
const { address } = request.params;
const { min_satoshi, no_cache } = request.query;

let utxosCache = null;
const utxos = await fastify.utxoSyncer.getUtxosByAddress(address, no_cache === 'true');
if (env.UTXO_SYNC_DATA_CACHE_ENABLE) {
if (no_cache !== 'true') {
utxosCache = await fastify.utxoSyncer.getUTXOsFromCache(address);
}
await fastify.utxoSyncer.enqueueSyncJob(address);
}
const utxos = utxosCache ? utxosCache : await fastify.bitcoin.getAddressTxsUtxo({ address });

return utxos.reduce(
(acc: Balance, utxo: UTXO) => {
if (utxo.status.confirmed) {
if (min_satoshi && utxo.value < min_satoshi) {
acc.dust_satoshi += utxo.value;
} else {
acc.satoshi += utxo.value;
}
return acc;
}
acc.pending_satoshi += utxo.value;
return acc;
},
{
address,
satoshi: 0,
pending_satoshi: 0,
dust_satoshi: 0,
utxo_count: utxos.length,
},

const rgbppUtxoCellsPairs = await fastify.rgbppCollector.getRgbppUtxoCellsPairs(
address,
utxos,
no_cache === 'true',
);
if (env.RGBPP_COLLECT_DATA_CACHE_ENABLE) {
await fastify.rgbppCollector.enqueueCollectJob(address, utxos);
}

const rgbppUtxoMap = rgbppUtxoCellsPairs.reduce((map, { utxo }) => {
map.set(utxo.txid + ':' + utxo.vout, utxo);
return map;
}, new Map<string, UTXO>());

const balance: Balance = {
address,
total_satoshi: 0,
satoshi: 0,
available_satoshi: 0,
pending_satoshi: 0,
dust_satoshi: 0,
rgbpp_satoshi: 0,
utxo_count: utxos.length,
};

for (const utxo of utxos) {
const isDustUTXO = min_satoshi !== undefined && utxo.value < min_satoshi;
const isRgbppBound = rgbppUtxoMap.has(utxo.txid + ':' + utxo.vout);

balance.total_satoshi += utxo.value;
if (utxo.status.confirmed) {
if (!isDustUTXO && !isRgbppBound) {
balance.available_satoshi += utxo.value;
}
if (isDustUTXO) {
balance.dust_satoshi += utxo.value;
}
if (isRgbppBound) {
balance.rgbpp_satoshi += utxo.value;
}
} else {
balance.pending_satoshi += utxo.value;
}
}
// @deprecated for compatibility
balance.satoshi = balance.available_satoshi;
return balance;
},
);

Expand All @@ -90,6 +112,10 @@ const addressRoutes: FastifyPluginCallback<Record<never, never>, Server, ZodType
.default('true')
.describe('Only return confirmed UTXOs'),
min_satoshi: z.coerce.number().optional().describe('The minimum value of the UTXO in satoshi'),
only_non_rgbpp_utxos: z
.enum(['true', 'false', 'undefined'])
.default('false')
.describe('Only return non-RGBPP UTXOs'),
no_cache: z
.enum(['true', 'false'])
.default('false')
Expand All @@ -102,28 +128,41 @@ const addressRoutes: FastifyPluginCallback<Record<never, never>, Server, ZodType
},
async function (request) {
const { address } = request.params;
const { only_confirmed, min_satoshi, no_cache } = request.query;
const { only_confirmed, min_satoshi, only_non_rgbpp_utxos, no_cache } = request.query;

let utxosCache = null;
const utxos = await fastify.utxoSyncer.getUtxosByAddress(address, no_cache === 'true');
if (env.UTXO_SYNC_DATA_CACHE_ENABLE) {
if (no_cache !== 'true') {
utxosCache = await fastify.utxoSyncer.getUTXOsFromCache(address);
}
await fastify.utxoSyncer.enqueueSyncJob(address);
}
let utxos = utxosCache ? utxosCache : await fastify.bitcoin.getAddressTxsUtxo({ address });
if (utxosCache) {
fastify.log.debug(`[UTXO] get utxos from cache: ${address}`);

const rgbppUtxoCellsPairs =
only_non_rgbpp_utxos === 'true'
? await fastify.rgbppCollector.getRgbppUtxoCellsPairs(address, utxos, no_cache === 'true')
: [];
if (env.RGBPP_COLLECT_DATA_CACHE_ENABLE) {
await fastify.rgbppCollector.enqueueCollectJob(address, utxos);
}
const rgbppUtxoSet = new Set(rgbppUtxoCellsPairs.map((pair) => pair.utxo.txid + ':' + pair.utxo.vout));

// compatible with the case where only_confirmed is undefined
if (only_confirmed === 'true' || only_confirmed === 'undefined') {
utxos = utxos.filter((utxo) => utxo.status.confirmed);
const conditions: ((utxo: UTXO) => boolean)[] = [];
if (only_confirmed === 'true') {
conditions.push((utxo: UTXO) => utxo.status.confirmed);
}
if (min_satoshi !== undefined) {
conditions.push((utxo: UTXO) => utxo.value >= min_satoshi);
}
if (min_satoshi) {
utxos = utxos.filter((utxo) => utxo.value >= min_satoshi);
if (only_non_rgbpp_utxos === 'true') {
conditions.push((utxo: UTXO) => !rgbppUtxoSet.has(utxo.txid + ':' + utxo.vout));
}
return utxos;

if (conditions.length === 0) {
return utxos;
}

return utxos.filter((utxo) => {
const pass = conditions.every((condition) => condition(utxo));
return pass;
});
},
);

Expand Down
2 changes: 2 additions & 0 deletions src/routes/bitcoin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import { ZodTypeProvider } from 'fastify-type-provider-zod';
import BitcoinClient from '../../services/bitcoin';
import feesRoutes from './fees';
import UTXOSyncer from '../../services/utxo';
import RgbppCollector from '../../services/rgbpp';

const bitcoinRoutes: FastifyPluginCallback<Record<never, never>, Server, ZodTypeProvider> = (fastify, _, done) => {
fastify.decorate('bitcoin', container.resolve<BitcoinClient>('bitcoin'));
fastify.decorate('utxoSyncer', container.resolve<UTXOSyncer>('utxoSyncer'));
fastify.decorate('rgbppCollector', container.resolve<RgbppCollector>('rgbppCollector'));

fastify.register(infoRoute);
fastify.register(blockRoutes, { prefix: '/block' });
Expand Down
9 changes: 6 additions & 3 deletions src/routes/bitcoin/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ export const Status = z.object({

export const Balance = z.object({
address: z.string(),
satoshi: z.number(),
pending_satoshi: z.number(),
dust_satoshi: z.number(),
total_satoshi: z.number().describe('Total balance in satoshi (available + pending + dust/rgbpp-bound)'),
pending_satoshi: z.number().describe('Pending balance in satoshi (unconfirmed)'),
satoshi: z.number().describe('@deprecated Use available_satoshi'),
available_satoshi: z.number().describe('Available balance in satoshi (confirmed and not dust/rgbpp-bound)'),
dust_satoshi: z.number().describe('Dust balance in satoshi (confirmed and below min_satoshi threshold)'),
rgbpp_satoshi: z.number().describe('RGB++ bound balance in satoshi (confirmed and RGB++ bound)'),
utxo_count: z.number(),
});

Expand Down
Loading

0 comments on commit aa1f43e

Please sign in to comment.