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

2.1: Feature: stack-increase for PoX-2 #3282

Merged
merged 10 commits into from
Sep 21, 2022
Merged

Conversation

kantai
Copy link
Member

@kantai kantai commented Sep 7, 2022

This PR adds two new methods to pox-2:

  • stack-increase: this method increases the lockup for the stacker, and adds the new amount to the reward sets of the remaining cycles for the user
  • delegate-stack-increase: this method increases the lockup for the supplied stacker, adding the new amount to the partially-stacked state

As part of this work, this also removes the total-ustx field from the stacking-state map. The rationale for this is to normalize some of the state in the PoX-2 contract: this field is not used for any checks, but it would be "replicated" in several other states: that's at least the stx-account lock amount and the reward-set entries for the stacker in each cycle. Because of the "increase" methods, the total-ustx field would either be out of sync with the increased amount or the previous cycle entries. To keep this field meaningful, it would need to be a list of total-ustx for each cycle, but because the field isn't used in the contract anywhere then it seemed better to just remove the state.

@codecov
Copy link

codecov bot commented Sep 7, 2022

Codecov Report

Merging #3282 (ad1ffc1) into feat/pox-2-unlock (4270820) will decrease coverage by 0.07%.
The diff coverage is 0.33%.

@@                  Coverage Diff                  @@
##           feat/pox-2-unlock    #3282      +/-   ##
=====================================================
- Coverage              29.91%   29.84%   -0.08%     
=====================================================
  Files                    279      279              
  Lines                 228223   228818     +595     
=====================================================
+ Hits                   68282    68287       +5     
- Misses                159941   160531     +590     
Impacted Files Coverage Δ
clarity/src/vm/database/structures.rs 62.72% <0.00%> (-4.46%) ⬇️
src/chainstate/stacks/boot/mod.rs 9.25% <0.00%> (-0.02%) ⬇️
src/chainstate/stacks/boot/pox_2_tests.rs 0.00% <0.00%> (ø)
src/chainstate/stacks/db/accounts.rs 43.90% <0.00%> (-1.36%) ⬇️
src/chainstate/stacks/mod.rs 8.02% <0.00%> (-0.07%) ⬇️
src/clarity_vm/special.rs 48.23% <1.81%> (-12.77%) ⬇️
src/clarity_vm/database/mod.rs 73.28% <100.00%> (-0.26%) ⬇️
src/burnchains/bitcoin/network.rs 77.77% <0.00%> (-3.71%) ⬇️
src/chainstate/stacks/index/cache.rs 13.37% <0.00%> (-0.51%) ⬇️
... and 15 more

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@zone117x
Copy link
Member

zone117x commented Sep 9, 2022

Closes #2533

(referencing the issue for anyone following along, it won't let me link the issue from the sidebar)

@@ -63,8 +64,6 @@
(define-map stacking-state
{ stacker: principal }
{
;; how many uSTX locked?
amount-ustx: uint,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think you could provide a read-only function that returns the number of locked tokens for a principal, via stx-account? Asking because I'm pretty sure stacking.club depends on this information (and there could be others).

(let ((existing-entry (unwrap-panic (map-get? reward-cycle-pox-address-list { reward-cycle: reward-cycle, index: reward-cycle-index })))
(existing-total (unwrap-panic (map-get? reward-cycle-total-stacked { reward-cycle: reward-cycle }))))
;; stacker must match
(asserts! (is-eq (get stacker existing-entry) (some (get stacker data))) none)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If (is-some (get stacker data)) is true, then wouldn't this assertion's failure be a Really Bad Thing, i.e. indicative that reward-cycle-pox-address-list was corrupted somehow, since the reward-cycle-index didn't refer to a PoX address from this stacker?

I can see why (get stacker data) could be none -- e.g. when the stacker had stacked through a delegate. But, should this function even be called when this is the case (or, can we not tell prior to calling that this is the case)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this would be a Really Bad Thing, but Clarity cannot assert a node panic, so instead, we just panic the transaction.

reward-cycle: (get first-reward-cycle stacker-state),
stacker: tx-sender,
add-amount: increase-by })))
(err ERR_STACKING_UNREACHABLE))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if this (fold increase-reward-cycle-entry) is always supposed to be (some ..), then doesn't that mean that internally, tx-sender must not have stacked through a delegate? Can we check this as part of the checks above this line?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, will add a check.


let mut snapshot = db.get_stx_balance_snapshot(principal);

if !snapshot.has_locked_tokens() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find myself wondering whether or not these Err(..) paths are ever reachable. If the Clarity code for pox-2 is correct, then these should never be hit, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see we panic() later in the special case handler.

Copy link
Member

@jcnelson jcnelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This overall LGTM, modulo the failing unit test. Just had a few questions about how defensive we can be in the stack-increase.

@jcnelson
Copy link
Member

N.B from blockchain meeting:

  • Increase code coverage in pox-2 to verify that the bi-directional map between stackers and the reward set state remains consistent. Pertaining to this, it's stack-increase, delegate-stack-increase, auto-unlock, and stack-extend. We should spend some time convincing ourselves that the structure of this map is preserved in all cases in which these are called.

Copy link
Contributor

@pavitthrap pavitthrap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, just had some suggestions wrt comments & readability

(err ERR_STACK_EXTEND_NOT_LOCKED))
(asserts! (>= increase-by u1)
(err ERR_STACKING_INVALID_AMOUNT))
(asserts! (>= (get unlocked stacker-info) increase-by)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could define amount_unlocked in the let and use that instead of (get unlocked stacker-info)

(map-set reward-cycle-pox-address-list
{ reward-cycle: reward-cycle, index: reward-cycle-index }
{ pox-addr: (get pox-addr existing-entry),
total-ustx: (+ (get total-ustx existing-entry)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can compute total-ustx in the let (it's computed twice here)

;; stacker must have delegated to the caller
(let ((delegation-info (unwrap! (get-check-delegation stacker) (err ERR_STACKING_PERMISSION_DENIED))))
;; must have delegated to tx-sender
(asserts! (is-eq (get delegated-to delegation-info) tx-sender)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these asserts would be easier to read if you moved the (get _ delegation-info) to the let

cycle_number,
&bob_principal,
);
assert_eq!(partial_stacked, 512 * POX_THRESHOLD_STEPS_USTX);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can use alice_first_lock_amount here

assert_eq!(alice_txs.len() as u64, 2);
assert_eq!(bob_txs.len() as u64, 5);

assert_eq!(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be helpful to possibly include the name of the associated error (from the pox contract) as part of the comments here


// submit an increase: this should fail, because Alice is not yet locked
let fail_no_lock_tx = alice_nonce;
let alice_increase = make_pox_2_increase(&alice, alice_nonce, 512 * POX_THRESHOLD_STEPS_USTX);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you define 512 * POX_THRESHOLD_STEPS_USTX as a variable in this test too?

assert_eq!(alice_txs.len() as u64, alice_nonce);

// transaction should fail because lock isn't applied
assert_eq!(&alice_txs[&fail_no_lock_tx].result.to_string(), "(err 26)");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could also include error "name" in the comments

@kantai kantai merged commit ef63920 into feat/pox-2-unlock Sep 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

PoX Updates: stack-increase
4 participants