stacks-network / stacks-core

The Stacks blockchain implementation
https://docs.stacks.co
GNU General Public License v3.0
3k stars 659 forks source link

[Stacks 2.1] Emit events for PoX operations and STX locked balance updates #3289

Closed zone117x closed 1 year ago

zone117x commented 1 year ago

This is a partial blocker for PoX-2 support in the API (and clients that depend on PoX related features in the API).

Every operation that changes PoX state should emit an event that includes both the operation-specific data, and global state for the given account.

For example, with a stack-extend:

{
  /* The current available balance, as string quoted micro-STX */
  balance: string,
  /* [PoX] The amount of locked STX, as string quoted micro-STX. Zero if no tokens are locked. */
  locked: string,
  /* [PoX] The burnchain block height of when the tokens unlock. Zero if no tokens are locked. */
  burnchain_unlock_height: number,
  /* [PoX] Details specific to the PoX operation */
  operation: {
    name: 'stacks-extend',
    args: {
      extend_count: number
    }
  }
}

These events can almost all be emitted through print statements in the PoX-2 contract, except for:

  1. The auto stack-unlock does not have an explicit contract-call function where we can include a print statement.
  2. It may be expensive (from a tx fee perspective) to lookup the info required to invoke these print statements. An event-emitter node already expects to spend more resources processing events -- but maybe unfair if users have to pay for regular miner nodes to generate the print data?

The API has two primary use cases for these events:

Determining an account's locked STX balance

See https://github.com/hirosystems/stacks-blockchain-api/issues/1277

Right now, Stacks 2.0 emits a stx_lock_event event which the API can store and query to determine locked STX. In PoX-2, this event is no longer enough to determine that state in given the new features in PoX-2 (e.g. stack-extend, auto stack-unlock, etc).

Parsing "PoX operations" in the Rosetta implementation

See https://github.com/hirosystems/stacks-blockchain-api/issues/1278

The Rosetta spec (used by at least a couple major exchanges) has a Data API which requires the API to generate "operations" for a given block. In order to create "PoX operations", the current implementation scans contract-call transactions for the PoX contract and the stack-stx function name, then manually parses Clarity args to generate a Stacking operation. This approach has major limitations:

  1. It's not aware of PoX operations that happen from contract-call or contract-deploy txs that call into the PoX contract -- the contract ID for tx will not be detected.
  2. For the new PoX-2 operations, we need to expand the Rosetta parsing logic. Instead of adding more hardcoded function names to parse, it would be much better to start consuming events.
kantai commented 1 year ago

The auto stack-unlock does not have an explicit contract-call function where we can include a print statement.

You can add print statements to the handle-unlock private function -- it gets invoked during the auto-unlock. Events from those invocations are all collected together. The current version in next doesn't create a transaction receipt for those events, but this branch adds a new synthetic transaction receipt to capture those:

https://github.com/stacks-network/stacks-blockchain/tree/feat/unlock-events

It may be expensive (from a tx fee perspective) to lookup the info required to invoke these print statements. An event-emitter node already expects to spend more resources processing events -- but maybe unfair if users have to pay for regular miner nodes to generate the print data?

How expensive? Is it doing additional data fetches, and if so, like how many per operation? If it's only 1-2 more data lookups, I'm not so concerned about it. If it's more than that, then we would have to move the event generation into the rust code.

zone117x commented 1 year ago

I think each print statement would need to call get-stacker-info, reward-cycle-to-burn-height, and stx-get-balance if we wanted to include the full STX balance payload mentioned above. It sounds like that would be alright to implement in pox-2 Clarity?

saralab commented 1 year ago

@pavitthrap Will help with this task once https://github.com/stacks-network/stacks-blockchain/issues/3284 is wrapped up this week.

kantai commented 1 year ago

I think each print statement would need to call get-stacker-info, reward-cycle-to-burn-height, and stx-get-balance if we wanted to include the full STX balance payload mentioned above. It sounds like that would be alright to implement in pox-2 Clarity?

Yep, that would all be fine to add to pox-2's contract. A lot of that information may be available without an additional lookup, too.

jcnelson commented 1 year ago

Could there be an "epoch transition" event emitted that indicated, among other things, the v1 unlock height?

jcnelson commented 1 year ago

The anchored block could also indicate its epoch.

donpdonp commented 1 year ago

3318 contains a patch to add pox_v1_unlock_height to the new_block event pushed to the API to help determine when the pox1 locked amounts become unlocked.

zone117x commented 1 year ago

This is closed by https://github.com/stacks-network/stacks-blockchain/pull/3318