Skip to content

Conversation

@setzeus
Copy link
Contributor

@setzeus setzeus commented Nov 25, 2023

PoX-4 Signing Key Stacking-State Update

Summary of Changes

This PR is meant to introduce, not complete, the core logic around signing keys in PoX-4 & address #4057 . The focus is specifically on updating the 'stacking-state' map & all the functions that read & write from it. This includes updates to the following public functions:

  1. (stack-stx)
  2. (delegate-stack-stx)
  3. (stack-extend)
  4. (delegate-stack-extend)

what this does not include
Getters & setters to the new map 'reward-cycle-signing-keys,' that'll be in another PR. This PR also does not include any logic that'll be used in relevant issues #4058, #4059, & #3970.

Testing

How were these changes tested?

This was only tested locally for syntax errors / clarinet check.

What future testing should occur?

As soon as this is merged I'll open an issue with the user stories that require testing for @moodmosaic to work into pox_4_tests.rs.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@codecov
Copy link

codecov bot commented Nov 25, 2023

Codecov Report

Attention: 24 lines in your changes are missing coverage. Please review.

Comparison is base (8cffc38) 85.08% compared to head (166ac8f) 64.10%.
Report is 13 commits behind head on next.

Files Patch % Lines
...kslib/src/chainstate/stacks/boot/contract_tests.rs 0.00% 24 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             next    #4092       +/-   ##
===========================================
- Coverage   85.08%   64.10%   -20.99%     
===========================================
  Files         429      429               
  Lines      302009   302143      +134     
===========================================
- Hits       256976   193700    -63276     
- Misses      45033   108443    +63410     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@setzeus setzeus self-assigned this Nov 28, 2023
@setzeus
Copy link
Contributor Author

setzeus commented Nov 28, 2023

Additional context re: using 'delegate-stack-stx' vs. 'stack-aggregation-commit-index' to submit a pool's signing-key for delegates that registered without a signing-key here:

#4082

@setzeus
Copy link
Contributor Author

setzeus commented Nov 28, 2023

Note: per Clarity WG morning discussion it's been noted that our preferred workflow here is to actively work on a version of PoX-4 that exists in /contrib per #4094 & then periodically copy that over to the more hardened PoX-4 that'll live in /boot.

Once #4094 is merged in I'll make these adjust only to the PoX-4 version in /contrib for now.

(unless there's reasonable push back on this workflow)

delegated-to: (optional principal)
delegated-to: (optional principal),
;; signing key for Nakamoto+, only 'none' when delegated & before delegate calls 'stack-aggregation-commit-indexed
signing-key: (optional (buff 33))
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like this could just be (buff 33) rather than an (optional (buff 33)): the delegate sets this value in delegate-stack-stx, which is also the first time the stacker-state is instantiated for the delegator.

Copy link
Contributor

Choose a reason for hiding this comment

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

Does it make sense to allow delegators enforce a signing key? If yes, should it be stored in a separate map?

Copy link
Member

Choose a reason for hiding this comment

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

Does it make sense to allow delegators enforce a signing key? If yes, should it be stored in a separate map?

Why would the delegator call delegate-stack-stx if the user supplied the wrong key?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I meant the user/pool member. My question does not make sense here.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree, that stack-aggregation-commit can't change the signing key.

Copy link
Contributor

@kantai kantai left a comment

Choose a reason for hiding this comment

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

Echoing Jude's comments, and just had a few more

@kantai
Copy link
Contributor

kantai commented Nov 30, 2023

@setzeus -- this patch adds a unit test which would check that the contract instantiates:

diff --git a/stackslib/src/chainstate/stacks/boot/contract_tests.rs b/stackslib/src/chainstate/stacks/boot/contract_tests.rs
index bd7941f73..d8450f0e7 100644
--- a/stackslib/src/chainstate/stacks/boot/contract_tests.rs
+++ b/stackslib/src/chainstate/stacks/boot/contract_tests.rs
@@ -60,6 +60,8 @@ lazy_static! {
     pub static ref POX_CONTRACT_TESTNET: QualifiedContractIdentifier = boot_code_id("pox", false);
     pub static ref POX_2_CONTRACT_TESTNET: QualifiedContractIdentifier =
         boot_code_id("pox-2", false);
+    pub static ref POX_4_CONTRACT_TESTNET: QualifiedContractIdentifier =
+        boot_code_id("pox-4", false);
     pub static ref COST_VOTING_CONTRACT_TESTNET: QualifiedContractIdentifier =
         boot_code_id("cost-voting", false);
     pub static ref USER_KEYS: Vec<StacksPrivateKey> =
@@ -559,6 +561,31 @@ impl HeadersDB for TestSimHeadersDB {
     }
 }
 
+#[test]
+fn pox_4_instantiates() {
+    let mut sim = ClarityTestSim::new();
+    sim.epoch_bounds = vec![0, 1, 2];
+    let delegator = StacksPrivateKey::new();
+
+    let expected_unlock_height = POX_TESTNET_CYCLE_LENGTH * 4;
+
+    // execute past 2.1 epoch initialization
+    sim.execute_next_block(|_env| {});
+    sim.execute_next_block(|_env| {});
+    sim.execute_next_block(|_env| {});
+
+    sim.execute_next_block(|env| {
+        env.initialize_versioned_contract(
+            POX_4_CONTRACT_TESTNET.clone(),
+            ClarityVersion::Clarity2,
+            &boot::POX_4_TESTNET_CODE,
+            None,
+            ASTRules::PrecheckSize,
+        )
+        .unwrap()
+    });
+}
+
 #[test]
 fn pox_2_contract_caller_units() {
     let mut sim = ClarityTestSim::new();

The test passes with the most recent changes:

$ cargo test pox_4_instantiates
...
running 1 test
test chainstate::stacks::boot::contract_tests::pox_4_instantiates ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1105 filtered out; finished in 0.04s
...

It also (correctly) fails if applied to the commit 6771f81.

Copy link
Contributor

@friedger friedger left a comment

Choose a reason for hiding this comment

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

I try to understand whether the same logic for the pox-address should be applied for the signing key for pools: If the pool operator decides to use a different signer key, the pool members rewards are not really at risk. However, would pool members like to decide whether the pool operator can delegate to one or the other signer? I think yes, therefore delegate-stx should also contain a signing key in the delegation-state

@friedger
Copy link
Contributor

friedger commented Dec 1, 2023

@setzeus There at least one rust functions that create stack-stx transactions with 4 instead of 5 arguments that makes the unit tests fail.
I found one in blocks.rs: https://github.com/stacks-network/stacks-blockchain/blob/cef8f87c59d326b5d30d9f2e6baf258d820da6b1/stackslib/src/chainstate/stacks/db/blocks.rs#L4222

from the logs of the test:

WARN [1701440351.250362] [stackslib/src/chainstate/stacks/db/transactions.rs:1045] [chainstate::nakamoto::coordinator::tests::test_simple_nakamoto_coordinator_10_tenures_10_blocks] Contract-call encountered an analysis error at runtime, contract_name: ST000000000000000000002AMW42H.pox-4, function_name: stack-stx, function_args: [u1000000000000000000, (tuple (hashbytes 0x253029fcdb225da88ef8434ed2bd32ff353983cf) (version 0x00)), u34, u12], error: IncorrectArgumentCount(5, 4)

@setzeus
Copy link
Contributor Author

setzeus commented Dec 1, 2023

Ahhh okay, thx @friedger, so updating PoX-4 stacking parameters broke existing tests somewhere else* I follow. Looking into it.

@setzeus setzeus requested a review from friedger December 4, 2023 21:03
@muneeb-ali
Copy link
Member

Great to see the changes approved here! 🚀

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.

Thank you for updating the stacking interfaces with these new methods! Before merging, I must insist that you add unit tests for them. It's not enough to see that PoX-4 instantiates; you must also verify that the public keys get added to the stacking state. Thanks!

let mut test_signers = TestSigners::default();
let mut peer = boot_nakamoto(function_name!(), vec![], test_signers.aggregate_public_key);
let private_key = peer.config.private_key.clone();
//let mut peer = boot_nakamoto(function_name!(), vec![], test_signers.aggregate_public_key);
Copy link
Member

Choose a reason for hiding this comment

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

Please remove dead code

let private_key = peer.config.private_key.clone();
//let mut peer = boot_nakamoto(function_name!(), vec![], test_signers.aggregate_public_key);
//let private_key = peer.config.private_key.clone();
let private_key = StacksPrivateKey::new();
Copy link
Member

Choose a reason for hiding this comment

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

Why is this a new key? Can you continue to please use the same key so we get consistent output?

Copy link
Contributor Author

@setzeus setzeus Dec 7, 2023

Choose a reason for hiding this comment

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

Recommendation from @kantai to pass/debug those unit tests, reverting back to commented out above I get in both places where I switched out peer.config for a new private key:

 let private_key = peer.config.private_key.clone();
    |                       ^^^^ not found in this scope

Copy link
Member

Choose a reason for hiding this comment

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

The problem is because you've commented out the code that instantiates peer

@jcnelson
Copy link
Member

jcnelson commented Dec 7, 2023

An update from the testing WG. This PR is blocked on getting the pox_4.rs tests in place, which is being handled in #4106. Once this is in place, it should be merged into this PR, so then it will become possible to test that the signing keys were indeed set.

(pox-addr { version: (buff 1), hashbytes: (buff 32) })
(start-burn-ht uint)
(lock-period uint))
(lock-period uint)
Copy link
Member

Choose a reason for hiding this comment

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

Same here -- can you add a comment to the method doc about the signing key?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated a sentence & added the following to comment doc above function:

;; * You need to provide a signing-key used to allocate signature-weight to a valid signer

Some(AddressHashMode::SerializeP2PKH),
);

let public_key = StacksPublicKey::from_private(&self.miner_key);
Copy link
Member

Choose a reason for hiding this comment

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

I think there instead needs to be a separate signing_key field in MockamotoNode. Same for the Nakamoto node. Perhaps it can be part of the Keychain?

Copy link
Contributor

@moodmosaic moodmosaic left a comment

Choose a reason for hiding this comment

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

It would be nice with some tests to ensure everything works as intended:

  1. signing-key in stacking-state:

    • Verify that the signing-key is correctly set.
  2. Modified Functions (stack-stx, delegate-stack-stx, etc.):

    • Ensure all functions modified to include the signing-key handle it correctly.
  3. stack-extend, delegate-stack-extend:

    • Test handling of updated-signing-key, ensuring proper updates in the stacking state.
  4. get-signer-info-for-cycle:

    • Verify retrieval of correct signer info for various inputs.

@jcnelson, @setzeus, could you share your thoughts on these test cases or suggest additional ones that might be relevant?

(define-constant ERR_DELEGATION_WRONG_REWARD_SLOT 29)
(define-constant ERR_STACKING_IS_DELEGATED 30)
(define-constant ERR_STACKING_NOT_DELEGATED 31)
(define-constant ERR_STACK_EXTEND_NO_SIGNING_KEY 32)
Copy link
Contributor

Choose a reason for hiding this comment

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

Where is this constant used?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unused, removed.

@setzeus setzeus force-pushed the feat/pox-4-signing-keys branch from 214d72d to 81273b6 Compare December 19, 2023 02:54
@setzeus setzeus mentioned this pull request Dec 19, 2023
8 tasks
@jcnelson
Copy link
Member

@moodmosaic Yes, please test all of those in pox_4_tests.rs.

cases[0].nameOwner.address),
]);
assertEquals(block.height, 2);
assertEquals(block.height, 3);
Copy link
Member

Choose a reason for hiding this comment

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

This looks like there was an off-by-one error somewhere, with all these changes. Can you elaborate more on why all of these block heights are now +1?

Copy link
Contributor

Choose a reason for hiding this comment

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

The pox-4 is in a different epoch than bns, therefore booting needs one more block

POX_4_NAME,
"stack-extend",
vec![Value::UInt(lock_period), addr_tuple],
vec![Value::UInt(lock_period), addr_tuple, Value::Optional(OptionalData {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.

Don't pass None; instead, make this an argument in Rust which gets passed to stack-extend.

(define-constant ADDRESS_VERSION_NATIVE_P2WPKH 0x04)
(define-constant ADDRESS_VERSION_NATIVE_P2WSH 0x05)
(define-constant ADDRESS_VERSION_NATIVE_P2TR 0x06)
;; (define-constant ADDRESS_VERSION_NATIVE_P2WPKH 0x04)
Copy link
Member

Choose a reason for hiding this comment

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

Please don't commit commented-out code

;; These first four correspond to address hash modes in Stacks 2.1,
;; and are defined in pox-mainnet.clar and pox-testnet.clar (so they
;; cannot be defined here again).
;; (define-constant ADDRESS_VERSION_P2PKH 0x00)
Copy link
Member

Choose a reason for hiding this comment

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

If you're now using is-in-mainnet instead of a separate pox-4-mainnet.clar, then where are these constants defined now?


;; Is the given burn block height in the prepare phase?
;; This computes `((height - first-burnchain-block-height) + pox-prepare-cycle-length) % pox-reward-cycle-length) < pox-prepare-cycle-length`.
(define-read-only (check-prepare-phase (height uint))
Copy link
Member

Choose a reason for hiding this comment

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

@setzeus This needs to be in #4164

(err ERR_STACKING_INVALID_LOCK_PERIOD))

;; stacking must not happen during prepare phase
(asserts! (not (check-prepare-phase burn-block-height))
Copy link
Member

Choose a reason for hiding this comment

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

Please revert this -- it has not been decided yet that stacking will be disabled in the prepare phase

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. Reverting all the work here to un-do rebasing from #4094.

@moodmosaic moodmosaic force-pushed the feat/pox-4-signing-keys branch from 81273b6 to 72ca439 Compare December 19, 2023 16:35
(start-burn-ht uint)
(lock-period uint))
(lock-period uint)
(signing-key (buff 33)))
Copy link
Contributor

@moodmosaic moodmosaic Dec 21, 2023

Choose a reason for hiding this comment

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

@jcnelson, we'd like to get this method (delegate-stack-stx) under test, with @setzeus. In this diff, there's the signing-key key that's added.

Looking at PoX-3 tests, some candidates to copy over to PoX-4 are

All of these tests seem to call into delegate-stack-stx. The question is:

  1. Are all those tests relevant in the context of PoX-4
  2. Which one would be the best to start with, so it can be added into this PR.

@setzeus
Copy link
Contributor Author

setzeus commented Dec 22, 2023

Work picked up by @MarvinJanssen in #4209 to add required tests in addition to base tests - changing to draft until #4209 is merged in then will close.

@setzeus setzeus marked this pull request as draft December 22, 2023 14:37
@setzeus
Copy link
Contributor Author

setzeus commented Jan 3, 2024

Closing since #4209 is now merged in.

@setzeus setzeus closed this Jan 3, 2024
@blockstack-devops
Copy link
Contributor

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@stacks-network stacks-network locked as resolved and limited conversation to collaborators Nov 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

8 participants