[Stacks 2.1] Support PoX-2 in Rosetta stacking operations
See related issue https://github.com/hirosystems/stacks-blockchain-api/issues/1277 which goes over similar details and questions around PoX-2.
The Rosetta implementation currently contains rosetta-operations for initiating a Stacking transaction. It also returns a synthetic "stx-unlocked" operation when querying for a block operations, where the block corresponds to an unlock height provided in the Stacks node stx_lock_event event.
This was initially implemented in PR https://github.com/hirosystems/stacks-blockchain-api/pull/689
At a high level, here are the changes required to ensure Rosetta Stacking functionality works with Pox-2:
PoX address format changes
PoX-2 functions will support segwit/taproot/bech32 addresses. See https://github.com/stacks-network/stacks-blockchain/issues/2586. This means the function signatures that used to use { (hashbytes (buff 20)) (version (buff 1)) } will be switched to { (hashbytes (buff 32)) (version (buff 1)) } (32 hashbytes instead of 20). The allowed version bytes will also be expanded to include new address formats. Various areas of code that assumed a 1-to-1 conversion between a STX and BTC address (C32 and B58) need to be refactored -- as the new BTC address formats cannot be represented as STX addresses.
Constructing Stacking Operations
Rosetta has built-in support for performing various "Stacking" operations, which under the hood perform PoX-1 contract calls. These need to be changed to PoX-2 contract calls. IIRC, only the stack-stx operation is currently fully supported, and the code for the delegate-stx and revoke-delegate-stx isn't fully supported or tested. See code around RosettaOperationType.DelegateStx: https://github.com/hirosystems/stacks-blockchain-api/blob/aceb7afdc1b27d36603cb0acb167d2262c3d5360/src/api/routes/rosetta/construction.ts#L207-L248
Parsing Stacking Operations
When Rosetta is queried for a given block or transaction, it parses existing txs to display the various "Stacking" operations. This is done by scanning for hardcoded PoX-1 contract principals and contract function names. This need to support parsing PoX-2 contract calls as well. See code around here: https://github.com/hirosystems/stacks-blockchain-api/blob/aceb7afdc1b27d36603cb0acb167d2262c3d5360/src/rosetta-helpers.ts#L578-L586
New PoX-2 Stacking Operations
The following new PoX-2 operations need supported (for both parsing and construction the associated Rosetta operations):
stack-extendhttps://github.com/stacks-network/stacks-blockchain/pull/2755stack-unlockhttps://github.com/stacks-network/stacks-blockchain/issues/2534stack-increasehttps://github.com/stacks-network/stacks-blockchain/issues/2533delegate-stack-extend(can potentially be skipped if we don't add additional support for the delegated stacking operations) https://github.com/stacks-network/stacks-blockchain/pull/2755
Note: blocked by https://github.com/hirosystems/stacks-blockchain-api/issues/1277 (and on the associated questions around stx_lock_event behavior for the new PoX-2 operations).
@kantai, follow-up to https://github.com/hirosystems/stacks-blockchain-api/issues/1277#issuecomment-1218346400, after evaluating the current Rosetta implementation, I think we do need explicit events (print or otherwise) for the outcomes of the various stacking operations.
(Note it would also still be helpful to have that higher level StxBalanceUpdate event you proposed so the API doesn't have to evaluate event deltas to derive the current locked state).
The current Rosetta code for parsing Stacking operations is brittle. It scans for hardcoded PoX contract principals and contract function names, then parses the input args in order to generate a Stacking operation. IIUC, this means that if Stacking is initiated by another contract calling into PoX, then the Rosetta layer will be missing those operations.
I'm also somewhat wary of continuing the "contract-call-arg parsing" approach for the new Stacking operations. Seems like reading a PoX event is a lot less brittle and more future-proof. Thoughts?
Update: MVP for PoX-2 support in Rosetta can just be parity with current PoX-1 support. That narrows the scope down to only supporting the stack-stx operation in PoX-2, and potentially only supporting legacy B58 bitcoin addresses (depends on how much more work and testing is required to get new bitcoin address formats supported).
This MVP still requires new logic in the tx construction where /v2/pox must be queried to determine which PoX contract ID should be used.
Additionally, there's a period of time where stack-stx operations can fail during the PoX-2 phase transitions. We can either A) let the Rosetta layer generate stacks-stx txs that will fail later on when it gets mined, or B) detect if the tx will fail and return an error to the client immediately.
The MVP approach described in the previous comment was implemented in https://github.com/hirosystems/stacks-blockchain-api/pull/1339
The following critical issues still need addressed:
- ~~At the end of "period 2" (when all PoX-1 locked state is force unlocked at time PoX-2 is activated) -- the Stacks node does not emit events for these unlocks. Consumers using Rosetta will still operate as if the locks from PoX-1 are still in effect. This can be solved by implementing new "stack-unlock" operations in the Rosetta layer when the associated events are implemented in the stacks-blockchain -- see blocking issue https://github.com/stacks-network/stacks-blockchain/issues/3289~~
- EDIT: implemented in https://github.com/hirosystems/stacks-blockchain-api/pull/1403
- ~~New Stacking operations such as
stack-extendandstack-increaseare not implemented as new Rosetta operations. The constructing of these operations can be implemented later on after 2.1 launch, however, thelocked STXamount changed by these operations is not reflected in the existing Rosetta data/parse endpoints, which can lead to Rosetta consumers ending up with an incorrectlocked STXamount for a given account.~~- EDIT: implemented in https://github.com/hirosystems/stacks-blockchain-api/pull/1403
- ~~End-to-end testing with the new Bitcoin address formats (segwit) when used as a PoX reward recipient address. It should work since there is new code to handle the new addresses, but it is not fully tested. Blocked on https://github.com/stacks-network/stacks-blockchain/pull/3283~~
- EDIT: the strikeout bullet above has been implemented
Update: all but one of the remaining tasks for this issue are now complete.
@janniks is working on the last issue in PR https://github.com/hirosystems/stacks-blockchain-api/pull/1454
Last task resolved in https://github.com/hirosystems/stacks-blockchain-api/pull/1454