Skip to content

Commit 1c6e35a

Browse files
authored
feat: support custom chain_id (e.g. for subnets) (#1669)
* feat: support custom chain_id (e.g. for subnets) * feat: add chain_id config sanity check during init * ci: lint fix
1 parent b050b1b commit 1c6e35a

File tree

22 files changed

+168
-73
lines changed

22 files changed

+168
-73
lines changed

.env

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ STACKS_CORE_RPC_PORT=20443
8787
## configure the chainID/networkID; testnet: 0x80000000, mainnet: 0x00000001
8888
STACKS_CHAIN_ID=0x00000001
8989

90+
# configure custom testnet and mainnet chainIDs for other networks such as subnets,
91+
# multiple values can be set using comma-separated key-value pairs.
92+
# TODO: currently configured with the default subnet testnet ID, the mainnet values
93+
# are placeholders that should be replaced with the actual subnet mainnet chainID
94+
CUSTOM_CHAIN_IDS=testnet=0x55005500,mainnet=12345678,mainnet=0xdeadbeaf
95+
9096
# Seconds to allow API components to shut down gracefully before force-killing them, defaults to 60
9197
# STACKS_SHUTDOWN_FORCE_KILL_TIMEOUT=60
9298

src/api/controllers/db-controller.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
abiFunctionToString,
3-
ChainID,
43
ClarityAbi,
54
ClarityAbiFunction,
65
getTypeString,
@@ -61,7 +60,7 @@ import {
6160
StxUnlockEvent,
6261
DbPox2Event,
6362
} from '../../datastore/common';
64-
import { unwrapOptional, FoundOrNot, unixEpochToIso, EMPTY_HASH_256 } from '../../helpers';
63+
import { unwrapOptional, FoundOrNot, unixEpochToIso, EMPTY_HASH_256, ChainID } from '../../helpers';
6564
import { serializePostCondition, serializePostConditionMode } from '../serializers/post-conditions';
6665
import { getOperations, parseTransactionMemo } from '../../rosetta-helpers';
6766
import { PgStore } from '../../datastore/pg-store';

src/api/init.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,13 @@ import { createRosettaMempoolRouter } from './routes/rosetta/mempool';
1919
import { createRosettaBlockRouter } from './routes/rosetta/block';
2020
import { createRosettaAccountRouter } from './routes/rosetta/account';
2121
import { createRosettaConstructionRouter } from './routes/rosetta/construction';
22-
import { apiDocumentationUrl, isProdEnv, waiter } from '../helpers';
22+
import { ChainID, apiDocumentationUrl, getChainIDNetwork, isProdEnv, waiter } from '../helpers';
2323
import { InvalidRequestError } from '../errors';
2424
import { createBurnchainRouter } from './routes/burnchain';
2525
import { createBnsNamespacesRouter } from './routes/bns/namespaces';
2626
import { createBnsPriceRouter } from './routes/bns/pricing';
2727
import { createBnsNamesRouter } from './routes/bns/names';
2828
import { createBnsAddressesRouter } from './routes/bns/addresses';
29-
30-
import { ChainID } from '@stacks/transactions';
31-
3229
import * as pathToRegex from 'path-to-regexp';
3330
import * as expressListEndpoints from 'express-list-endpoints';
3431
import { createMiddleware as createPrometheusMiddleware } from '@promster/express';
@@ -214,7 +211,7 @@ export async function startApiServer(opts: {
214211
router.use('/fee_rate', createFeeRateRouter(datastore));
215212
router.use('/tokens', createTokenRouter(datastore));
216213
router.use('/pox2_events', createPox2EventsRouter(datastore));
217-
if (chainId !== ChainID.Mainnet && writeDatastore) {
214+
if (getChainIDNetwork(chainId) === 'testnet' && writeDatastore) {
218215
router.use('/faucets', createFaucetRouter(writeDatastore));
219216
}
220217
return router;

src/api/rosetta-constants.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as T from '@stacks/stacks-blockchain-api-types';
22
import { RosettaErrorNoDetails } from '@stacks/stacks-blockchain-api-types';
3-
import { ChainID } from '@stacks/transactions';
3+
import { ChainID, getChainIDNetwork } from '../helpers';
44

55
export const RosettaNetworks = {
66
testnet: 'testnet',
@@ -20,9 +20,9 @@ export const RosettaConstants = {
2020
};
2121

2222
export function getRosettaNetworkName(chainId: ChainID): string {
23-
if (chainId === ChainID.Mainnet) {
23+
if (getChainIDNetwork(chainId) === 'mainnet') {
2424
return RosettaNetworks.mainnet;
25-
} else if (chainId === ChainID.Testnet) {
25+
} else if (getChainIDNetwork(chainId) === 'testnet') {
2626
return RosettaNetworks.testnet;
2727
} else {
2828
throw new Error(`Cannot get rosetta network for unexpected chainID "${chainId}"`);

src/api/routes/address.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
validatePrincipal,
1111
} from '../query-helpers';
1212
import {
13+
ChainID,
1314
formatMapToObject,
1415
getSendManyContract,
1516
has0xPrefix,
@@ -39,7 +40,6 @@ import {
3940
AddressNonces,
4041
NftEvent,
4142
} from '@stacks/stacks-blockchain-api-types';
42-
import { ChainID } from '@stacks/transactions';
4343
import { decodeClarityValueToRepr } from 'stacks-encoding-native-js';
4444
import { validate } from '../validate';
4545
import { NextFunction, Request, Response } from 'express';

src/api/routes/bns/addresses.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as express from 'express';
22
import { asyncHandler } from '../../async-handler';
33
import { PgStore } from '../../../datastore/pg-store';
44
import { isUnanchoredRequest } from '../../query-helpers';
5-
import { ChainID } from '@stacks/transactions';
5+
import { ChainID } from '../../../helpers';
66
import {
77
getETagCacheHandler,
88
setETagCacheHeaders,

src/api/routes/bns/names.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { parsePagingQueryInput } from '../../../api/pagination';
55
import { isUnanchoredRequest } from '../../query-helpers';
66
import { bnsBlockchain, BnsErrors } from '../../../event-stream/bns/bns-constants';
77
import { BnsGetNameInfoResponse } from '@stacks/stacks-blockchain-api-types';
8-
import { ChainID } from '@stacks/transactions';
8+
import { ChainID } from '../../../helpers';
99
import {
1010
getETagCacheHandler,
1111
setETagCacheHeaders,

src/api/routes/bns/pricing.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@ import {
88
bufferCVFromString,
99
callReadOnlyFunction,
1010
ClarityType,
11-
ChainID,
1211
} from '@stacks/transactions';
1312
import {
1413
BnsGetNamePriceResponse,
1514
BnsGetNamespacePriceResponse,
1615
} from '@stacks/stacks-blockchain-api-types';
17-
import { isValidPrincipal } from './../../../helpers';
16+
import { ChainID, getChainIDNetwork, isValidPrincipal } from './../../../helpers';
1817
import { PgStore } from '../../../datastore/pg-store';
1918
import { getBnsContractID, GetStacksNetwork } from '../../../event-stream/bns/bns-helpers';
2019
import { logger } from '../../../logger';
@@ -34,7 +33,9 @@ export function createBnsPriceRouter(db: PgStore, chainId: ChainID): express.Rou
3433
const randomPrivKey = makeRandomPrivKey();
3534
const address = getAddressFromPrivateKey(
3635
randomPrivKey.data,
37-
chainId === ChainID.Mainnet ? TransactionVersion.Mainnet : TransactionVersion.Testnet
36+
getChainIDNetwork(chainId) === 'mainnet'
37+
? TransactionVersion.Mainnet
38+
: TransactionVersion.Testnet
3839
);
3940
const bnsContractIdentifier = getBnsContractID(chainId);
4041
if (!bnsContractIdentifier || !isValidPrincipal(bnsContractIdentifier)) {
@@ -87,7 +88,9 @@ export function createBnsPriceRouter(db: PgStore, chainId: ChainID): express.Rou
8788
const randomPrivKey = makeRandomPrivKey();
8889
const address = getAddressFromPrivateKey(
8990
randomPrivKey.data,
90-
chainId === ChainID.Mainnet ? TransactionVersion.Mainnet : TransactionVersion.Testnet
91+
getChainIDNetwork(chainId) === 'mainnet'
92+
? TransactionVersion.Mainnet
93+
: TransactionVersion.Testnet
9194
);
9295

9396
const bnsContractIdentifier = getBnsContractID(chainId);

src/api/routes/debug.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,12 @@ import {
2929
tupleCV,
3030
bufferCV,
3131
AnchorMode,
32-
ChainID,
3332
deserializeTransaction,
3433
} from '@stacks/transactions';
3534
import { StacksTestnet } from '@stacks/network';
3635
import { SampleContracts } from '../../sample-data/broadcast-contract-default';
3736
import { ClarityAbi, getTypeString, encodeClarityValue } from '../../event-stream/contract-abi';
38-
import { cssEscape, unwrapOptional } from '../../helpers';
37+
import { NETWORK_CHAIN_ID, cssEscape, unwrapOptional } from '../../helpers';
3938
import { StacksCoreRpcClient, getCoreNodeEndpoint } from '../../core-rpc/client';
4039
import { PgStore } from '../../datastore/pg-store';
4140
import { DbTx } from '../../datastore/common';
@@ -580,7 +579,7 @@ export function createDebugRouter(db: PgStore): express.Router {
580579

581580
const rosettaNetwork = {
582581
blockchain: RosettaConstants.blockchain,
583-
network: getRosettaNetworkName(ChainID.Testnet),
582+
network: getRosettaNetworkName(NETWORK_CHAIN_ID.testnet),
584583
};
585584

586585
async function stackWithRosetta(

src/api/routes/rosetta/account.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as express from 'express';
22
import { asyncHandler } from '../../async-handler';
33
import { DbBlock } from '../../../datastore/common';
44
import { PgStore } from '../../../datastore/pg-store';
5-
import { has0xPrefix, FoundOrNot } from '../../../helpers';
5+
import { has0xPrefix, FoundOrNot, ChainID } from '../../../helpers';
66
import {
77
RosettaAccount,
88
RosettaBlockIdentifier,
@@ -13,7 +13,6 @@ import {
1313
} from '@stacks/stacks-blockchain-api-types';
1414
import { RosettaErrors, RosettaConstants, RosettaErrorsTypes } from '../../rosetta-constants';
1515
import { rosettaValidateRequest, ValidSchema, makeRosettaError } from '../../rosetta-validate';
16-
import { ChainID } from '@stacks/transactions';
1716
import { getValidatedFtMetadata } from '../../../rosetta-helpers';
1817
import { isFtMetadataEnabled } from '../../../token-metadata/helpers';
1918

0 commit comments

Comments
 (0)