Skip to content

Commit

Permalink
fix(rosetta): support tenure change transactions (#2128)
Browse files Browse the repository at this point in the history
* fix: support tenure change transactions in rosetta

* test: add test for rosetta tenure-change tx

---------

Co-authored-by: Matthew Little <zone117x@gmail.com>
  • Loading branch information
rafaelcr and zone117x authored Oct 21, 2024
1 parent f17106a commit bfbf65c
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/api/controllers/db-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export function getTxTypeString(typeId: DbTxTypeId): Transaction['tx_type'] {
return 'poison_microblock';
case DbTxTypeId.Coinbase:
case DbTxTypeId.CoinbaseToAltRecipient:
case DbTxTypeId.NakamotoCoinbase:
return 'coinbase';
case DbTxTypeId.TenureChange:
return 'tenure_change';
Expand All @@ -145,7 +146,7 @@ function getTxAnchorModeString(anchorMode: number): TransactionAnchorModeType {
}
}

function getTxTenureChangeCauseString(cause: number) {
export function getTxTenureChangeCauseString(cause: number) {
switch (cause) {
case 0:
return 'block_found';
Expand Down
3 changes: 2 additions & 1 deletion src/api/rosetta-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export enum RosettaOperationType {
StackStx = 'stack_stx',
DelegateStx = 'delegate_stx',
RevokeDelegateStx = 'revoke_delegate_stx',
// todo: add new pox-2 methods
TenureChange = 'tenure_change',
}

type RosettaOperationTypeUnion = `${RosettaOperationType}`;
Expand All @@ -77,6 +77,7 @@ export const RosettaOperationTypes = arrayOfAllOpTypes([
'stack_stx',
'delegate_stx',
'revoke_delegate_stx',
'tenure_change',
]) as RosettaOperationType[];

export const RosettaOperationStatuses = [
Expand Down
21 changes: 21 additions & 0 deletions src/rosetta/rosetta-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import * as btc from 'bitcoinjs-lib';
import {
getTxFromDataStore,
getTxStatus,
getTxTenureChangeCauseString,
getTxTypeString,
parseContractCallMetadata,
} from '../api/controllers/db-controller';
Expand Down Expand Up @@ -170,6 +171,9 @@ async function getOperationsInternal(
case RosettaOperationType.PoisonMicroblock:
operations.push(makePoisonMicroblockOperation(tx, 0));
break;
case RosettaOperationType.TenureChange:
operations.push(makeTenureChangeOperation(tx, operations.length));
break;
default:
throw new Error(`Unexpected tx type: ${JSON.stringify(txType)}`);
}
Expand Down Expand Up @@ -727,6 +731,23 @@ function makePoisonMicroblockOperation(tx: BaseTx, index: number): RosettaOperat
return sender;
}

function makeTenureChangeOperation(tx: BaseTx, index: number): RosettaOperation {
return {
operation_identifier: { index: index },
type: RosettaOperationType.TenureChange,
status: getTxStatus(tx.status),
metadata: {
tenure_consensus_hash: tx.tenure_change_tenure_consensus_hash as string,
prev_tenure_consensus_hash: tx.tenure_change_prev_tenure_consensus_hash as string,
burn_view_consensus_hash: tx.tenure_change_burn_view_consensus_hash as string,
previous_tenure_end: tx.tenure_change_previous_tenure_end as string,
previous_tenure_blocks: tx.tenure_change_previous_tenure_blocks as number,
cause: getTxTenureChangeCauseString(tx.tenure_change_cause as number),
pubkey_hash: tx.tenure_change_pubkey_hash as string,
},
};
}

export function publicKeyToBitcoinAddress(publicKey: string, network: string): string | undefined {
const publicKeyBuffer = Buffer.from(publicKey, 'hex');

Expand Down
127 changes: 127 additions & 0 deletions tests/rosetta/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,133 @@ describe('Rosetta API', () => {
});
});

test('epoch3 tenure-change block/transaction', async () => {
const parentData = new TestBlockBuilder().addTx().build();
const block1: TestBlockArgs = {
block_height: 2,
block_hash: '0xd0dd05e3d0a1bd60640c9d9d30d57012ffe47b52fe643140c39199c757d37e3f',
index_block_hash: '0x6a36c14514047074c2877065809bbb70d81d52507747f4616da997deb7228fad',
parent_index_block_hash: parentData.block.index_block_hash,
parent_block_hash: parentData.block.block_hash,
parent_microblock_hash: '0x0000000000000000000000000000000000000000000000000000000000000000',
burn_block_hash: '0xfe15c0d3ebe314fad720a08b839a004c2e6386f5aecc19ec74807d1920cb6aeb',
miner_txid: '0x0000000000000000000000000000000000000000000000000000000000000000',
};
const txTenureChange1: TestTxArgs = {
tx_id: '0xc152de9376bab4fc27291c9cd088643698290a12bb511d768f873cb3d280eb48',
tx_index: 1,
type_id: DbTxTypeId.TenureChange,
status: DbTxStatus.Success,
raw_result: '0x0703',
canonical: true,
microblock_canonical: true,
microblock_sequence: 2147483647,
microblock_hash: '0x00',
fee_rate: 0n,
sender_address: 'ST1HB1T8WRNBYB0Y3T7WXZS38NKKPTBR3EG9EPJKR',
tenure_change_tenure_consensus_hash: '0x2fedd90a5f318ed8cec419fd1c6656b5af452497',
tenure_change_prev_tenure_consensus_hash: '0x5104aae6d442b49c8e8d2031df7f40b67528e654',
tenure_change_burn_view_consensus_hash: '0x2fedd90a5f318ed8cec419fd1c6656b5af452497',
tenure_change_previous_tenure_end:
'0xb77b061202b1e6dce889ba1633efa969d3c24679d32a7542d29015ee94e8a860',
tenure_change_previous_tenure_blocks: 9,
tenure_change_cause: 0,
tenure_change_pubkey_hash: '0x62b4273562dfa3825496094507564bf2b30c8b11',
};
const blockData1 = new TestBlockBuilder(block1).addTx(txTenureChange1).build();

await db.update(parentData);
await db.update(blockData1);

const query1 = await supertest(api.server)
.post(`/rosetta/v1/block/transaction`)
.send({
network_identifier: { blockchain: 'stacks', network: 'testnet' },
block_identifier: {
index: blockData1.block.block_height,
hash: blockData1.block.block_hash,
},
transaction_identifier: { hash: txTenureChange1.tx_id },
});
expect(query1.status).toBe(200);
expect(query1.type).toBe('application/json');
expect(query1.body).toEqual({
transaction_identifier: {
hash: txTenureChange1.tx_id,
},
operations: [
{
operation_identifier: {
index: 0,
},
type: 'tenure_change',
status: 'success',
metadata: {
tenure_consensus_hash: txTenureChange1.tenure_change_tenure_consensus_hash,
prev_tenure_consensus_hash: txTenureChange1.tenure_change_prev_tenure_consensus_hash,
burn_view_consensus_hash: txTenureChange1.tenure_change_burn_view_consensus_hash,
previous_tenure_end: txTenureChange1.tenure_change_previous_tenure_end,
previous_tenure_blocks: txTenureChange1.tenure_change_previous_tenure_blocks,
cause: 'block_found',
pubkey_hash: txTenureChange1.tenure_change_pubkey_hash,
},
},
],
});

const query2 = await supertest(api.address)
.post(`/rosetta/v1/block`)
.send({
network_identifier: { blockchain: 'stacks', network: 'testnet' },
block_identifier: { index: blockData1.block.block_height },
});
expect(query1.status).toBe(200);
expect(query1.type).toBe('application/json');
const expected: RosettaBlockResponse = {
block: {
block_identifier: {
index: blockData1.block.block_height,
hash: blockData1.block.block_hash,
},
parent_block_identifier: {
index: blockData1.block.block_height - 1,
hash: blockData1.block.parent_block_hash,
},
timestamp: blockData1.block.burn_block_time * 1000,
transactions: [
{
transaction_identifier: {
hash: txTenureChange1.tx_id as string,
},
operations: [
{
operation_identifier: {
index: 0,
},
type: 'tenure_change',
status: 'success',
metadata: {
tenure_consensus_hash: txTenureChange1.tenure_change_tenure_consensus_hash,
prev_tenure_consensus_hash:
txTenureChange1.tenure_change_prev_tenure_consensus_hash,
burn_view_consensus_hash: txTenureChange1.tenure_change_burn_view_consensus_hash,
previous_tenure_end: txTenureChange1.tenure_change_previous_tenure_end,
previous_tenure_blocks: txTenureChange1.tenure_change_previous_tenure_blocks,
cause: 'block_found',
pubkey_hash: txTenureChange1.tenure_change_pubkey_hash,
},
},
],
},
],
metadata: {
burn_block_height: blockData1.block.burn_block_height,
},
},
};
expect(query2.body).toEqual(expected);
});

test('block/transaction - invalid transaction hash', async () => {
const query1 = await supertest(api.server)
.post(`/rosetta/v1/block/transaction`)
Expand Down

0 comments on commit bfbf65c

Please sign in to comment.