Skip to content

Commit e262280

Browse files
committed
test: add rosetta stacking for each block height
1 parent 2476345 commit e262280

File tree

3 files changed

+7
-193
lines changed

3 files changed

+7
-193
lines changed

src/test-utils/test-helpers.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,7 @@ export async function standByForTxSuccess(expectedTxId: string): Promise<DbTx> {
263263
return tx;
264264
}
265265

266-
// todo: add `export` to this and remove other implementations of this
267-
async function standByUntilBlock(blockHeight: number): Promise<DbBlock> {
266+
export async function standByUntilBlock(blockHeight: number): Promise<DbBlock> {
268267
const dbBlock = await new Promise<DbBlock>(async resolve => {
269268
const listener: (blockHash: string) => void = async blockHash => {
270269
const dbBlockQuery = await testEnv.api.datastore.getBlock({ hash: blockHash });

src/tests-2.1-transition/pox-transition.ts

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
getRosettaBlockByBurnBlockHeight,
3030
stackStxWithRosetta,
3131
standByForAccountUnlock,
32+
standByUntilBlock,
3233
} from '../test-utils/test-helpers';
3334
import { decodeClarityValue } from 'stacks-encoding-native-js';
3435
import { ApiServer } from '../api/init';
@@ -112,43 +113,6 @@ describe('PoX transition tests', () => {
112113
return tx;
113114
}
114115

115-
async function standByUntilBlock(blockHeight: number): Promise<DbBlock> {
116-
const dbBlock = await new Promise<DbBlock>(async resolve => {
117-
const listener: (blockHash: string) => void = async blockHash => {
118-
const dbBlockQuery = await api.datastore.getBlock({ hash: blockHash });
119-
if (!dbBlockQuery.found || dbBlockQuery.result.block_height < blockHeight) {
120-
return;
121-
}
122-
api.datastore.eventEmitter.removeListener('blockUpdate', listener);
123-
resolve(dbBlockQuery.result);
124-
};
125-
api.datastore.eventEmitter.addListener('blockUpdate', listener);
126-
127-
// Check if block height already reached
128-
const curHeight = await api.datastore.getCurrentBlockHeight();
129-
if (curHeight.found && curHeight.result >= blockHeight) {
130-
const dbBlock = await api.datastore.getBlock({ height: curHeight.result });
131-
if (!dbBlock.found) {
132-
throw new Error('Unhandled missing block');
133-
}
134-
api.datastore.eventEmitter.removeListener('blockUpdate', listener);
135-
resolve(dbBlock.result);
136-
return;
137-
}
138-
});
139-
140-
// Ensure stacks-node is caught up with processing this block
141-
while (true) {
142-
const nodeInfo = await client.getInfo();
143-
if (nodeInfo.stacks_tip_height >= blockHeight) {
144-
break;
145-
} else {
146-
await timeout(50);
147-
}
148-
}
149-
return dbBlock;
150-
}
151-
152116
async function standByUntilBurnBlock(burnBlockHeight: number): Promise<DbBlock> {
153117
const dbBlock = await new Promise<DbBlock>(async resolve => {
154118
const listener: (blockHash: string) => void = async blockHash => {

src/tests-2.1/pox-2-rosetta.ts

Lines changed: 5 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
stackStxWithRosetta,
2929
standByForAccountUnlock,
3030
standByForTxSuccess,
31+
standByUntilBlock,
3132
standByUntilBurnBlock,
3233
testEnv,
3334
TestEnvContext,
@@ -77,156 +78,6 @@ describe('PoX-2 - Rosetta - Stacking with segwit', () => {
7778
});
7879
});
7980

80-
const rosettaNetwork: NetworkIdentifier = {
81-
blockchain: RosettaConstants.blockchain,
82-
network: getRosettaNetworkName(ChainID.Testnet),
83-
};
84-
85-
async function fetchRosetta<TPostBody, TRes>(endpoint: string, body: TPostBody) {
86-
const result = await supertest(api.server)
87-
.post(endpoint)
88-
.send(body as any);
89-
expect(result.status).toBe(200);
90-
expect(result.type).toBe('application/json');
91-
return result.body as TRes;
92-
}
93-
94-
async function getRosettaBlockByHeight(blockHeight: number) {
95-
const dbBlockQuery = await api.datastore.getBlock({ height: blockHeight });
96-
if (!dbBlockQuery.found) {
97-
throw new Error(`block ${blockHeight} not found`);
98-
}
99-
return fetchRosetta<RosettaBlockRequest, RosettaBlockResponse>('/rosetta/v1/block', {
100-
network_identifier: { blockchain: 'stacks', network: 'testnet' },
101-
block_identifier: { hash: dbBlockQuery.result.block_hash },
102-
});
103-
}
104-
105-
async function getRosettaBlockByBurnBlockHeight(burnBlockHeight: number) {
106-
const unlockDbBlock = await api.datastore.getBlockByBurnBlockHeight(burnBlockHeight);
107-
expect(unlockDbBlock.found).toBeTruthy();
108-
return fetchRosetta<RosettaBlockRequest, RosettaBlockResponse>('/rosetta/v1/block', {
109-
network_identifier: { blockchain: 'stacks', network: 'testnet' },
110-
block_identifier: { hash: unlockDbBlock.result!.block_hash },
111-
});
112-
}
113-
114-
async function getRosettaAccountBalance(stacksAddress: string, atBlockHeight?: number) {
115-
const req: RosettaAccountBalanceRequest = {
116-
network_identifier: { blockchain: 'stacks', network: 'testnet' },
117-
account_identifier: { address: stacksAddress },
118-
};
119-
if (atBlockHeight) {
120-
req.block_identifier = { index: atBlockHeight };
121-
}
122-
const account = await fetchRosetta<RosettaAccountBalanceRequest, RosettaAccountBalanceResponse>(
123-
'/rosetta/v1/account/balance',
124-
req
125-
);
126-
// Also query for locked balance, requires specifying a special constant sub_account
127-
req.account_identifier.sub_account = { address: RosettaConstants.StackedBalance };
128-
const locked = await fetchRosetta<RosettaAccountBalanceRequest, RosettaAccountBalanceResponse>(
129-
'/rosetta/v1/account/balance',
130-
req
131-
);
132-
return {
133-
account,
134-
locked,
135-
};
136-
}
137-
138-
async function stackStxWithRosetta(opts: {
139-
btcAddr: string;
140-
stacksAddress: string;
141-
pubKey: string;
142-
privateKey: string;
143-
cycleCount: number;
144-
ustxAmount: bigint;
145-
}) {
146-
const stackingOperations: RosettaOperation[] = [
147-
{
148-
operation_identifier: { index: 0, network_index: 0 },
149-
related_operations: [],
150-
type: 'stack_stx',
151-
account: { address: opts.stacksAddress, metadata: {} },
152-
amount: {
153-
value: '-' + opts.ustxAmount.toString(),
154-
currency: { symbol: 'STX', decimals: 6 },
155-
metadata: {},
156-
},
157-
metadata: {
158-
number_of_cycles: opts.cycleCount,
159-
pox_addr: opts.btcAddr,
160-
},
161-
},
162-
{
163-
operation_identifier: { index: 1, network_index: 0 },
164-
related_operations: [],
165-
type: 'fee',
166-
account: { address: opts.stacksAddress, metadata: {} },
167-
amount: { value: '10000', currency: { symbol: 'STX', decimals: 6 } },
168-
},
169-
];
170-
171-
// preprocess
172-
const preprocessResult = await fetchRosetta<
173-
RosettaConstructionPreprocessRequest,
174-
RosettaConstructionPreprocessResponse
175-
>('/rosetta/v1/construction/preprocess', {
176-
network_identifier: rosettaNetwork,
177-
operations: stackingOperations,
178-
metadata: {},
179-
max_fee: [{ value: '12380898', currency: { symbol: 'STX', decimals: 6 }, metadata: {} }],
180-
suggested_fee_multiplier: 1,
181-
});
182-
183-
// metadata
184-
const metadataResult = await fetchRosetta<
185-
RosettaConstructionMetadataRequest,
186-
RosettaConstructionMetadataResponse
187-
>('/rosetta/v1/construction/metadata', {
188-
network_identifier: rosettaNetwork,
189-
options: preprocessResult.options!, // using options returned from preprocess
190-
public_keys: [{ hex_bytes: opts.pubKey, curve_type: 'secp256k1' }],
191-
});
192-
193-
// payload
194-
const payloadsResult = await fetchRosetta<
195-
RosettaConstructionPayloadsRequest,
196-
RosettaConstructionPayloadResponse
197-
>('/rosetta/v1/construction/payloads', {
198-
network_identifier: rosettaNetwork,
199-
operations: stackingOperations, // using same operations as preprocess request
200-
metadata: metadataResult.metadata, // using metadata from metadata response
201-
public_keys: [{ hex_bytes: opts.pubKey, curve_type: 'secp256k1' }],
202-
});
203-
204-
// sign tx
205-
const stacksTx = deserializeTransaction(payloadsResult.unsigned_transaction);
206-
const signer = new TransactionSigner(stacksTx);
207-
signer.signOrigin(createStacksPrivateKey(opts.privateKey));
208-
const signedSerializedTx = Buffer.from(stacksTx.serialize()).toString('hex');
209-
const expectedTxId = '0x' + stacksTx.txid();
210-
211-
// submit
212-
const submitResult = await fetchRosetta<
213-
RosettaConstructionSubmitRequest,
214-
RosettaConstructionSubmitResponse
215-
>('/rosetta/v1/construction/submit', {
216-
network_identifier: rosettaNetwork,
217-
signed_transaction: '0x' + signedSerializedTx,
218-
});
219-
220-
const txStandby = await standByForTxSuccess(expectedTxId);
221-
222-
return {
223-
txId: expectedTxId,
224-
tx: txStandby,
225-
submitResult,
226-
resultMetadata: metadataResult,
227-
};
228-
}
229-
23081
test('Fund new account for testing', async () => {
23182
await bitcoinRpcClient.importaddress({ address: btcAddr, label: btcAddr, rescan: false });
23283

@@ -283,8 +134,8 @@ describe('PoX-2 - Rosetta - Stacking with segwit', () => {
283134
ustxAmount: ustxAmount,
284135
});
285136

286-
expect(stackingResult.resultMetadata.metadata.contract_name).toBe('pox-2');
287-
expect(stackingResult.resultMetadata.metadata.burn_block_height as number).toBeTruthy();
137+
expect(stackingResult.constructionMetadata.metadata.contract_name).toBe('pox-2');
138+
expect(stackingResult.constructionMetadata.metadata.burn_block_height as number).toBeTruthy();
288139
expect(stackingResult.submitResult.transaction_identifier.hash).toBe(stackingResult.txId);
289140
expect(stackingResult.tx.contract_call_contract_id).toBe('ST000000000000000000002AMW42H.pox-2');
290141
});
@@ -401,8 +252,8 @@ describe('PoX-2 - Rosetta - Stacking with segwit', () => {
401252
ustxAmount,
402253
});
403254

404-
expect(rosettaStackStx.resultMetadata.metadata.contract_name).toBe('pox-2');
405-
expect(rosettaStackStx.resultMetadata.metadata.burn_block_height as number).toBeTruthy();
255+
expect(rosettaStackStx.constructionMetadata.metadata.contract_name).toBe('pox-2');
256+
expect(rosettaStackStx.constructionMetadata.metadata.burn_block_height as number).toBeTruthy();
406257
expect(rosettaStackStx.submitResult.transaction_identifier.hash).toBe(rosettaStackStx.txId);
407258
expect(rosettaStackStx.tx.contract_call_contract_id).toBe(
408259
'ST000000000000000000002AMW42H.pox-2'

0 commit comments

Comments
 (0)