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

Cut beta release #1979

Merged
merged 5 commits into from
May 14, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -921,7 +921,7 @@ jobs:
type=ref,event=pr
type=semver,pattern={{version}},value=${{ steps.semantic.outputs.new_release_version }},enable=${{ steps.semantic.outputs.new_release_version != '' }}
type=semver,pattern={{major}}.{{minor}},value=${{ steps.semantic.outputs.new_release_version }},enable=${{ steps.semantic.outputs.new_release_version != '' }}
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}

- name: Login to DockerHub
uses: docker/login-action@v3
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![CI](https://github.com/hirosystems/stacks-blockchain-api/actions/workflows/ci.yml/badge.svg)](https://github.com/hirosystems/stacks-blockchain-api/actions/workflows/ci.yml)
[![GitHub Releases](https://img.shields.io/github/v/release/hirosystems/stacks-blockchain-api?display_name=release)](https://github.com/hirosystems/stacks-blockchain-api/releases/latest)
[![Docker Pulls](https://img.shields.io/docker/pulls/blockstack/stacks-blockchain-api-standalone)](https://hub.docker.com/r/hirosystems/stacks-blockchain-api-standalone/)
[![Docker Pulls](https://img.shields.io/docker/pulls/blockstack/stacks-blockchain-api)](https://hub.docker.com/r/hirosystems/stacks-blockchain-api/)
[![NPM client package](https://img.shields.io/badge/npm-%40stacks%2Fblockchain--api--client-blue)](https://www.npmjs.org/package/@stacks/blockchain-api-client)

## Quick start
Expand Down
10 changes: 4 additions & 6 deletions client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,12 @@ await sub.unsubscribe();
### Socket.io

```js
import { io } from "socket.io-client";
import * as stacks from '@stacks/blockchain-api-client';
import { StacksApiSocketClient } from '@stacks/blockchain-api-client';

// for testnet, replace with https://api.testnet.hiro.so/
const socketUrl = "https://api.mainnet.hiro.so/";
// for testnet, replace with https://api.testnet.hiro.so
const socketUrl = "https://api.mainnet.hiro.so";

const socket = io(socketUrl);
const sc = new stacks.StacksApiSocketClient(socket);
const sc = new StacksApiSocketClient({ url: socketUrl });

sc.subscribeAddressTransactions('ST3GQB6WGCWKDNFNPSQRV8DY93JN06XPZ2ZE9EVMA', (address, tx) => {
console.log('address:', address);
Expand Down
3 changes: 3 additions & 0 deletions client/src/socket-io/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ function createStacksApiSocket(opts?: StacksApiSocketConnectionOptions) {
subscriptions: Array.from(new Set(opts?.subscriptions)).join(','),
},
};
if (!socketOpts.transports) {
socketOpts.transports = ['websocket'];
}
const socket: StacksApiSocket = io(getWsUrl(opts?.url ?? BASE_PATH).href, socketOpts);
return socket;
}
Expand Down
2 changes: 1 addition & 1 deletion docker/docker-compose.dev.stacks-blockchain.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: '3.7'
services:
stacks-blockchain:
image: 'hirosystems/stacks-api-e2e:stacks3.0-4d11d85'
image: 'hirosystems/stacks-api-e2e:stacks3.0-0a2c0e2'
restart: on-failure
environment:
STACKS_EVENT_OBSERVER: host.docker.internal:3700
Expand Down
2 changes: 1 addition & 1 deletion docker/docker-compose.dev.stacks-krypton.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: '3.7'
services:
stacks-blockchain:
image: 'hirosystems/stacks-api-e2e:stacks3.0-4d11d85'
image: 'hirosystems/stacks-api-e2e:stacks3.0-0a2c0e2'
ports:
- '18443:18443' # bitcoin regtest JSON-RPC interface
- '18444:18444' # bitcoin regtest p2p
Expand Down
7 changes: 6 additions & 1 deletion docs/api/rosetta/rosetta-network-status-response.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"current_block_identifier",
"current_block_timestamp",
"genesis_block_identifier",
"peers"
"peers",
"current_burn_block_height"
],
"properties": {
"current_block_identifier": {
Expand All @@ -31,6 +32,10 @@
"items": {
"$ref": "./../../entities/rosetta/rosetta-network-peers.schema.json"
}
},
"current_burn_block_height": {
"type": "integer",
"description": "The latest burn block height"
}
},
"additionalProperties": false
Expand Down
3 changes: 3 additions & 0 deletions docs/api/stacking/get-pox-cycle-signers.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@
"results": [
{
"signing_key": "0x038e3c4529395611be9abf6fa3b6987e81d402385e3d605a073f42f407565a4a3d",
"signer_address": "STRYYQQ9M8KAF4NS7WNZQYY59X93XEKR31JP64CP",
"stacked_amount": "686251350000000000",
"stacked_amount_percent": 50,
"weight": 5,
"weight_percent": 55.55555555555556
},
{
"signing_key": "0x029874497a7952483aa23890e9d0898696f33864d3df90939930a1f45421fe3b09",
"signer_address": "STF9B75ADQAVXQHNEQ6KGHXTG7JP305J2GRWF3A2",
"stacked_amount": "457500900000000000",
"stacked_amount_percent": 33.333333333333336,
"weight": 3,
"weight_percent": 33.33333333333333
},
{
"signing_key": "0x02dcde79b38787b72d8e5e0af81cffa802f0a3c8452d6b46e08859165f49a72736",
"signer_address": "ST18MDW2PDTBSCR1ACXYRJP2JX70FWNM6YY2VX4SS",
"stacked_amount": "228750450000000000",
"stacked_amount_percent": 16.666666666666668,
"weight": 1,
Expand Down
12 changes: 4 additions & 8 deletions docs/entities/rosetta/rosetta-block.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"type": "object",
"title": "RosettaBlock",
"description": "Blocks contain an array of Transactions that occurred at a particular BlockIdentifier. A hard requirement for blocks returned by Rosetta implementations is that they MUST be inalterable: once a client has requested and received a block identified by a specific BlockIndentifier, all future calls for that same BlockIdentifier must return the same block contents.",
"required": ["block_identifier", "parent_block_identifier", "timestamp", "transactions"],
"required": ["block_identifier", "parent_block_identifier", "timestamp", "transactions", "metadata"],
"additionalProperties": false,
"properties": {
"block_identifier": {
Expand All @@ -25,14 +25,10 @@
"metadata": {
"type": "object",
"description": "meta data",
"required": ["transactions_root", "difficulty"],
"required": ["burn_block_height"],
"properties": {
"transactions_root": {
"type": "string",
"description": ""
},
"difficulty": {
"type": "string",
"burn_block_height": {
"type": "number",
"description": ""
}
}
Expand Down
1 change: 1 addition & 0 deletions docs/entities/stacking/signer.example.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"signing_key": "0x038e3c4529395611be9abf6fa3b6987e81d402385e3d605a073f42f407565a4a3d",
"signer_address": "STRYYQQ9M8KAF4NS7WNZQYY59X93XEKR31JP64CP",
"stacked_amount": "686251350000000000",
"stacked_amount_percent": 50,
"weight": 5,
Expand Down
5 changes: 5 additions & 0 deletions docs/entities/stacking/signer.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"additionalProperties": false,
"required": [
"signing_key",
"signer_address",
"weight",
"stacked_amount",
"weight_percent",
Expand All @@ -13,6 +14,10 @@
"signing_key": {
"type": "string"
},
"signer_address": {
"type": "string",
"description": "The Stacks address derived from the signing_key."
},
"weight": {
"type": "integer"
},
Expand Down
16 changes: 13 additions & 3 deletions docs/generated.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,9 @@ export type AbstractTransaction = BaseTransaction & {
* An ISO 8601 (YYYY-MM-DDTHH:mm:ss.sssZ) indicating when this block was mined.
*/
block_time_iso: string;
/**
* Height of the anchor burn block.
*/
burn_block_height: number;
/**
* Unix timestamp (in seconds) indicating when this block was mined
Expand Down Expand Up @@ -2361,9 +2364,8 @@ export interface RosettaBlock {
/**
* meta data
*/
metadata?: {
transactions_root: string;
difficulty: string;
metadata: {
burn_block_height: number;
[k: string]: unknown | undefined;
};
}
Expand Down Expand Up @@ -3029,6 +3031,10 @@ export interface RosettaNetworkStatusResponse {
* Peers information
*/
peers: RosettaPeers[];
/**
* The latest burn block height
*/
current_burn_block_height: number;
}
/**
* The block_identifier uniquely identifies a block in a particular network.
Expand Down Expand Up @@ -3387,6 +3393,10 @@ export interface PoxCycleSignersListResponse {
}
export interface PoxSigner {
signing_key: string;
/**
* The Stacks address derived from the signing_key.
*/
signer_address: string;
weight: number;
stacked_amount: string;
weight_percent: number;
Expand Down
3 changes: 3 additions & 0 deletions src/api/controllers/db-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,9 @@ export async function getRosettaBlockFromDataStore(
parent_block_identifier,
timestamp: dbBlock.burn_block_time * 1000,
transactions: blockTxs.found ? blockTxs.result : [],
metadata: {
burn_block_height: dbBlock.burn_block_height,
},
};
return { found: true, result: apiBlock };
});
Expand Down
2 changes: 1 addition & 1 deletion src/api/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ export async function startApiServer(opts: {
v2.use('/smart-contracts', createV2SmartContractsRouter(datastore));
v2.use('/mempool', createMempoolRouter(datastore));
v2.use('/addresses', createV2AddressesRouter(datastore));
v2.use('/pox', createPoxRouter(datastore));
v2.use('/pox', createPoxRouter(datastore, chainId));
return v2;
})()
);
Expand Down
1 change: 1 addition & 0 deletions src/api/routes/rosetta/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export function createRosettaNetworkRouter(db: PgStore, chainId: ChainID): expre
hash: genesis.block_identifier.hash,
},
peers,
current_burn_block_height: block.metadata?.burn_block_height ?? 0,
};
const nodeInfo = await stacksCoreRpcClient.getInfo();
const referenceNodeTipHeight = nodeInfo.stacks_tip_height;
Expand Down
15 changes: 14 additions & 1 deletion src/api/routes/v2/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
parseDbTx,
} from '../../../api/controllers/db-controller';
import { decodeClarityValueToRepr } from 'stacks-encoding-native-js';
import { TransactionVersion, getAddressFromPublicKey } from '@stacks/transactions';

export function parseDbNakamotoBlock(block: DbBlock): NakamotoBlock {
const apiBlock: NakamotoBlock = {
Expand Down Expand Up @@ -175,9 +176,14 @@ export function parseDbPoxCycle(cycle: DbPoxCycle): PoxCycle {
return result;
}

export function parseDbPoxSigner(signer: DbPoxCycleSigner): PoxSigner {
export function parseDbPoxSigner(signer: DbPoxCycleSigner, isMainnet: boolean): PoxSigner {
const signerAddress = getAddressFromPublicKey(
Buffer.from(signer.signing_key.slice(2), 'hex'),
isMainnet ? TransactionVersion.Mainnet : TransactionVersion.Testnet
);
const result: PoxSigner = {
signing_key: signer.signing_key,
signer_address: signerAddress,
weight: signer.weight,
stacked_amount: signer.stacked_amount,
weight_percent: signer.weight_percent,
Expand All @@ -192,5 +198,12 @@ export function parseDbPoxSignerStacker(stacker: DbPoxCycleSignerStacker): PoxSt
stacked_amount: stacker.locked,
pox_address: stacker.pox_addr,
};
// Special handling for pool operator stackers
if (
stacker.name === 'stack-aggregation-commit-indexed' ||
stacker.name === 'stack-aggregation-commit'
) {
result.stacked_amount = stacker.amount_ustx;
}
return result;
}
12 changes: 8 additions & 4 deletions src/api/routes/v2/pox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ import {
PoxCycleListResponse,
PoxCycleSignerStackersListResponse,
PoxCycleSignersListResponse,
} from 'docs/generated';
PoxSigner,
} from '@stacks/stacks-blockchain-api-types';
import { parseDbPoxCycle, parseDbPoxSigner, parseDbPoxSignerStacker } from './helpers';
import { InvalidRequestError } from '../../../errors';
import { ChainID, getChainIDNetwork } from '../../../helpers';

export function createPoxRouter(db: PgStore): express.Router {
export function createPoxRouter(db: PgStore, chainId: ChainID): express.Router {
const router = express.Router();
const cacheHandler = getETagCacheHandler(db);
const isMainnet = getChainIDNetwork(chainId) === 'mainnet';

router.get(
'/cycles',
Expand Down Expand Up @@ -83,7 +86,7 @@ export function createPoxRouter(db: PgStore): express.Router {
limit,
offset,
total,
results: results.map(r => parseDbPoxSigner(r)),
results: results.map(r => parseDbPoxSigner(r, isMainnet)),
};
setETagCacheHeaders(res);
res.json(response);
Expand All @@ -110,8 +113,9 @@ export function createPoxRouter(db: PgStore): express.Router {
res.status(404).json({ error: `Not found` });
return;
}
const response: PoxSigner = parseDbPoxSigner(signer, isMainnet);
setETagCacheHeaders(res);
res.json(parseDbPoxSigner(signer));
res.json(response);
} catch (error) {
if (error instanceof InvalidRequestError) {
res.status(404).json({ errors: error.message });
Expand Down
2 changes: 2 additions & 0 deletions src/datastore/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,8 @@ export interface DbPoxCycleSignerStacker {
stacker: string;
locked: string;
pox_addr: string;
name: string;
amount_ustx: string;
}

interface ReOrgEntities {
Expand Down
2 changes: 1 addition & 1 deletion src/datastore/pg-store-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ export class PgStoreV2 extends BasePgStoreModule {
);
const results = await sql<(DbPoxCycleSignerStacker & { total: number })[]>`
WITH stackers AS (
SELECT DISTINCT ON (stacker) stacker, locked, pox_addr
SELECT DISTINCT ON (stacker) stacker, locked, pox_addr, amount_ustx, name
FROM pox4_events
WHERE canonical = true
AND microblock_canonical = true
Expand Down
12 changes: 8 additions & 4 deletions src/datastore/pg-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1938,8 +1938,10 @@ export class PgStore extends BasePgStore {
if (!dbTx.found) {
return { found: false };
}
const cols =
poxTable === 'pox4_events' ? POX4_SYNTHETIC_EVENT_COLUMNS : POX_SYNTHETIC_EVENT_COLUMNS;
const queryResults = await sql<PoxSyntheticEventQueryResult[]>`
SELECT ${sql(POX_SYNTHETIC_EVENT_COLUMNS)}
SELECT ${sql(cols)}
FROM ${sql(poxTable)}
WHERE canonical = true AND microblock_canonical = true AND tx_id = ${txId}
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC, event_index DESC
Expand All @@ -1957,8 +1959,10 @@ export class PgStore extends BasePgStore {
poxTable: PoxSyntheticEventTable;
}): Promise<FoundOrNot<DbPoxSyntheticEvent[]>> {
return await this.sqlTransaction(async sql => {
const cols =
poxTable === 'pox4_events' ? POX4_SYNTHETIC_EVENT_COLUMNS : POX_SYNTHETIC_EVENT_COLUMNS;
const queryResults = await sql<PoxSyntheticEventQueryResult[]>`
SELECT ${sql(POX_SYNTHETIC_EVENT_COLUMNS)}
SELECT ${sql(cols)}
FROM ${sql(poxTable)}
WHERE canonical = true AND microblock_canonical = true AND stacker = ${principal}
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC, event_index DESC
Expand Down Expand Up @@ -2349,7 +2353,7 @@ export class PgStore extends BasePgStore {
// Special case for `handle-unlock` which should be returned if it is the last received event.

const pox4EventQuery = await sql<PoxSyntheticEventQueryResult[]>`
SELECT ${sql(POX_SYNTHETIC_EVENT_COLUMNS)}
SELECT ${sql(POX4_SYNTHETIC_EVENT_COLUMNS)}
FROM pox4_events
WHERE canonical = true AND microblock_canonical = true AND stacker = ${stxAddress}
AND block_height <= ${blockHeight}
Expand Down Expand Up @@ -4243,7 +4247,7 @@ export class PgStore extends BasePgStore {

let poxV4Unlocks: StxLockEventResult[] = [];
const pox4EventQuery = await sql<PoxSyntheticEventQueryResult[]>`
SELECT DISTINCT ON (stacker) stacker, ${sql(POX_SYNTHETIC_EVENT_COLUMNS)}
SELECT DISTINCT ON (stacker) stacker, ${sql(POX4_SYNTHETIC_EVENT_COLUMNS)}
FROM pox4_events
WHERE canonical = true AND microblock_canonical = true
AND block_height <= ${block.block_height}
Expand Down
20 changes: 20 additions & 0 deletions src/tests-2.5/pox-4-delegate-aggregation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,26 @@ describe('PoX-4 - Delegate aggregation increase operations', () => {
name: 'stack-aggregation-commit-indexed',
pox_addr: delegateeAccount.btcTestnetAddr,
stacker: delegatorAccount.stxAddr,
data: expect.objectContaining({
signer_key: `0x${signerPubKey}`,
end_cycle_id: expect.stringMatching(/\d+/),
start_cycle_id: expect.stringMatching(/\d+/),
}),
})
);

const stackerRes: any = await fetchGet(`/extended/v1/pox4/stacker/${delegatorAccount.stxAddr}`);
expect(stackerRes).toBeDefined();
expect(stackerRes.results[0]).toEqual(
expect.objectContaining({
name: 'stack-aggregation-commit-indexed',
pox_addr: delegateeAccount.btcTestnetAddr,
stacker: delegatorAccount.stxAddr,
data: expect.objectContaining({
signer_key: `0x${signerPubKey}`,
end_cycle_id: expect.stringMatching(/\d+/),
start_cycle_id: expect.stringMatching(/\d+/),
}),
})
);
});
Expand Down
Loading
Loading