feat: allow signer-key allowances instead of signature

This commit is contained in:
Hank Stoever
2024-02-13 17:01:47 -08:00
parent 163c9b49dc
commit d8bf3ebf22
7 changed files with 74 additions and 39 deletions

View File

@@ -416,7 +416,7 @@ pub mod tests {
let program = format!(
r#"
{}
(verify-signer-key-sig {} u{} "{}" u{} 0x{} 0x{})
(verify-signer-key-sig {} u{} "{}" u{} (some 0x{}) 0x{})
"#,
&*POX_4_CODE, //s
Value::Tuple(pox_addr.clone().as_clarity_tuple().unwrap()), //p

View File

@@ -1860,7 +1860,7 @@ pub mod test {
addr_tuple,
Value::UInt(burn_ht as u128),
Value::UInt(lock_period),
Value::buff_from(signature).unwrap(),
Value::some(Value::buff_from(signature).unwrap()).unwrap(),
Value::buff_from(signer_key.to_bytes_compressed()).unwrap(),
],
)
@@ -2009,7 +2009,7 @@ pub mod test {
vec![
Value::UInt(lock_period),
addr_tuple,
Value::buff_from(signature).unwrap(),
Value::some(Value::buff_from(signature).unwrap()).unwrap(),
Value::buff_from(signer_key.to_bytes_compressed()).unwrap(),
],
)
@@ -2114,7 +2114,7 @@ pub mod test {
vec![
addr_tuple,
Value::UInt(reward_cycle),
Value::buff_from(signature).unwrap(),
Value::some(Value::buff_from(signature).unwrap()).unwrap(),
Value::buff_from(signer_key.to_bytes_compressed()).unwrap(),
],
)

View File

@@ -211,6 +211,19 @@
;; for the given reward cycle
(define-map aggregate-public-keys uint (buff 33))
;; State for setting allowances for signer keys to be used in
;; certain stacking transactions
(define-map signer-key-allowances
{
signer-key: (buff 33),
reward-cycle: uint,
period: uint,
topic: (string-ascii 12),
pox-addr: { version: (buff 1), hashbytes: (buff 32) },
}
bool
)
;; What's the reward cycle number of the burnchain block height?
;; Will runtime-abort if height is less than the first burnchain block (this is intentional)
(define-read-only (burn-height-to-reward-cycle (height uint))
@@ -576,7 +589,7 @@
(pox-addr (tuple (version (buff 1)) (hashbytes (buff 32))))
(start-burn-ht uint)
(lock-period uint)
(signer-sig (buff 65))
(signer-sig (optional (buff 65)))
(signer-key (buff 33)))
;; this stacker's first reward cycle is the _next_ reward cycle
(let ((first-reward-cycle (+ u1 (current-pox-reward-cycle)))
@@ -704,21 +717,30 @@
;; See `get-signer-key-message-hash` for details on the message hash.
;;
;; Note that `reward-cycle` corresponds to the _current_ reward cycle,
;; not the reward cycle at which the delegation will start.
;; The public key is recovered from the signature and compared to `signer-key`.
;; when used with `stack-stx` and `stack-extend`.
;; When `signer-sig` is present, the public key is recovered from the signature
;; and compared to `signer-key`.
;; If `signer-sig` is `none`, the function verifies that an allowance was previously
;; added for this key.
(define-read-only (verify-signer-key-sig (pox-addr { version: (buff 1), hashbytes: (buff 32) })
(reward-cycle uint)
(topic (string-ascii 12))
(period uint)
(signer-sig (buff 65))
(signer-sig-opt (optional (buff 65)))
(signer-key (buff 33)))
(ok (asserts!
(is-eq
(unwrap! (secp256k1-recover?
(get-signer-key-message-hash pox-addr reward-cycle topic period)
signer-sig) (err ERR_INVALID_SIGNATURE_RECOVER))
signer-key)
(err ERR_INVALID_SIGNATURE_PUBKEY))))
(match signer-sig-opt
signer-sig (ok (asserts!
(is-eq
(unwrap! (secp256k1-recover?
(get-signer-key-message-hash pox-addr reward-cycle topic period)
signer-sig) (err ERR_INVALID_SIGNATURE_RECOVER))
signer-key)
(err ERR_INVALID_SIGNATURE_PUBKEY)))
(begin
(ok (asserts! (default-to false (map-get? signer-key-allowances
{ signer-key: signer-key, reward-cycle: reward-cycle, period: period, topic: topic, pox-addr: pox-addr }))
(err ERR_NOT_ALLOWED)))
)))
;; Commit partially stacked STX and allocate a new PoX reward address slot.
;; This allows a stacker/delegate to lock fewer STX than the minimal threshold in multiple transactions,
@@ -734,7 +756,7 @@
;; *New in Stacks 2.1.*
(define-private (inner-stack-aggregation-commit (pox-addr { version: (buff 1), hashbytes: (buff 32) })
(reward-cycle uint)
(signer-sig (buff 65))
(signer-sig (optional (buff 65)))
(signer-key (buff 33)))
(let ((partial-stacked
;; fetch the partial commitments
@@ -777,7 +799,7 @@
;; Returns (err ...) on failure.
(define-public (stack-aggregation-commit (pox-addr { version: (buff 1), hashbytes: (buff 32) })
(reward-cycle uint)
(signer-sig (buff 65))
(signer-sig (optional (buff 65)))
(signer-key (buff 33)))
(match (inner-stack-aggregation-commit pox-addr reward-cycle signer-sig signer-key)
pox-addr-index (ok true)
@@ -787,7 +809,7 @@
;; *New in Stacks 2.1.*
(define-public (stack-aggregation-commit-indexed (pox-addr { version: (buff 1), hashbytes: (buff 32) })
(reward-cycle uint)
(signer-sig (buff 65))
(signer-sig (optional (buff 65)))
(signer-key (buff 33)))
(inner-stack-aggregation-commit pox-addr reward-cycle signer-sig signer-key))
@@ -1036,7 +1058,7 @@
;; used for signing. The `tx-sender` can thus decide to change the key when extending.
(define-public (stack-extend (extend-count uint)
(pox-addr { version: (buff 1), hashbytes: (buff 32) })
(signer-sig (buff 65))
(signer-sig (optional (buff 65)))
(signer-key (buff 33)))
(let ((stacker-info (stx-account tx-sender))
;; to extend, there must already be an etry in the stacking-state
@@ -1300,6 +1322,26 @@
(ok { stacker: stacker,
unlock-burn-height: new-unlock-ht }))))
;; Add an allowance for a signer key.
;; When an allowance is added, the `signer-sig` argument is not required
;; in the functions that use it as an argument.
;; The `allowed` flag can be used to either enable or disable the allowance.
;; Only the Stacks principal associated with `signer-key` can call this function.
;; *New in Stacks 3.0*
(define-public (set-signer-key-allowance (pox-addr { version: (buff 1), hashbytes: (buff 32)})
(period uint)
(reward-cycle uint)
(topic (string-ascii 12))
(signer-key (buff 33))
(allowed bool))
(begin
;; Validate that `tx-sender` has the same pubkey hash as `signer-key`
(asserts! (is-eq
(unwrap! (principal-construct? (if is-in-mainnet 0x16 0x1a) (hash160 signer-key)) (err ERR_INVALID_SIGNER_KEY))
tx-sender) (err ERR_NOT_ALLOWED))
(map-set signer-key-allowances { pox-addr: pox-addr, period: period, reward-cycle: reward-cycle, topic: topic, signer-key: signer-key } allowed)
(ok true)))
;; Get the _current_ PoX stacking delegation information for a stacker. If the information
;; is expired, or if there's never been such a stacker, then returns none.
;; *New in Stacks 2.1*

View File

@@ -1470,7 +1470,7 @@ fn verify_signer_key_sig(
LimitedCostTracker::new_free(),
|env| {
let program = format!(
"(verify-signer-key-sig {} u{} \"{}\" u{} 0x{} 0x{})",
"(verify-signer-key-sig {} u{} \"{}\" u{} (some 0x{}) 0x{})",
Value::Tuple(pox_addr.clone().as_clarity_tuple().unwrap()),
reward_cycle,
topic.get_name_str(),
@@ -2268,7 +2268,7 @@ fn stack_stx_signer_key() {
pox_addr_val.clone(),
Value::UInt(block_height as u128),
Value::UInt(2),
Value::buff_from(signature.clone()).unwrap(),
Value::some(Value::buff_from(signature.clone()).unwrap()).unwrap(),
signer_key_val.clone(),
],
)];
@@ -2384,7 +2384,7 @@ fn stack_extend_signer_key() {
vec![
Value::UInt(1),
pox_addr_val.clone(),
Value::buff_from(signature.clone()).unwrap(),
Value::some(Value::buff_from(signature.clone()).unwrap()).unwrap(),
signer_extend_key_val.clone(),
],
)];
@@ -2492,7 +2492,7 @@ fn delegate_stack_stx_signer_key() {
vec![
pox_addr_val.clone(),
Value::UInt(next_reward_cycle.into()),
Value::buff_from(signature).unwrap(),
Value::some(Value::buff_from(signature).unwrap()).unwrap(),
signer_key_val.clone(),
],
),
@@ -2661,7 +2661,7 @@ fn delegate_stack_stx_extend_signer_key() {
vec![
pox_addr.as_clarity_tuple().unwrap().into(),
Value::UInt(next_reward_cycle.into()),
Value::buff_from(signature).unwrap(),
Value::some(Value::buff_from(signature).unwrap()).unwrap(),
signer_key_val.clone(),
],
);
@@ -2681,7 +2681,7 @@ fn delegate_stack_stx_extend_signer_key() {
vec![
pox_addr.as_clarity_tuple().unwrap().into(),
Value::UInt(extend_cycle.into()),
Value::buff_from(extend_signature).unwrap(),
Value::some(Value::buff_from(extend_signature).unwrap()).unwrap(),
signer_extend_key_val.clone(),
],
);
@@ -2896,7 +2896,7 @@ fn delegate_stack_increase() {
vec![
pox_addr.as_clarity_tuple().unwrap().into(),
Value::UInt(next_reward_cycle.into()),
Value::buff_from(signature).unwrap(),
(Value::some(Value::buff_from(signature).unwrap()).unwrap()),
signer_key_val.clone(),
],
);

View File

@@ -250,15 +250,6 @@ pub mod pox4 {
CHAIN_ID_TESTNET,
lock_period,
);
println!(
"Hash: 0x{}",
to_hex(expected_hash_vec.as_bytes().as_slice())
);
println!(
"Pubkey: {}",
to_hex(pubkey.to_bytes_compressed().as_slice())
);
// println!("PoxAddr: {}", pox_addr_b58_serialize(&pox_addr).unwrap());
let expected_hash = expected_hash_vec.as_bytes();
// Test 1: valid result

View File

@@ -865,7 +865,7 @@ impl MockamotoNode {
pox_address.as_clarity_tuple().unwrap().into(),
ClarityValue::UInt(u128::from(parent_burn_height)),
ClarityValue::UInt(12),
ClarityValue::buff_from(signature).unwrap(),
ClarityValue::some(ClarityValue::buff_from(signature).unwrap()).unwrap(),
ClarityValue::buff_from(signer_key).unwrap(),
],
})
@@ -889,7 +889,7 @@ impl MockamotoNode {
function_args: vec![
ClarityValue::UInt(5),
pox_address.as_clarity_tuple().unwrap().into(),
ClarityValue::buff_from(signature).unwrap(),
ClarityValue::some(ClarityValue::buff_from(signature).unwrap()).unwrap(),
ClarityValue::buff_from(signer_key).unwrap(),
],
})

View File

@@ -416,7 +416,8 @@ pub fn boot_to_epoch_3(
pox_addr_tuple.clone(),
clarity::vm::Value::UInt(205),
clarity::vm::Value::UInt(12),
clarity::vm::Value::buff_from(signature).unwrap(),
clarity::vm::Value::some(clarity::vm::Value::buff_from(signature).unwrap())
.unwrap(),
clarity::vm::Value::buff_from(signer_pk.to_bytes_compressed()).unwrap(),
],
);
@@ -988,7 +989,8 @@ fn correct_burn_outs() {
pox_addr_tuple,
clarity::vm::Value::UInt(pox_info.current_burnchain_block_height.into()),
clarity::vm::Value::UInt(1),
clarity::vm::Value::buff_from(signature).unwrap(),
clarity::vm::Value::some(clarity::vm::Value::buff_from(signature).unwrap())
.unwrap(),
clarity::vm::Value::buff_from(pk_bytes).unwrap(),
],
);