Remove Miner

Diagram Flow

Complete Flow Influence

Explanations

This is a smart contract that allows for the removal of a miner from the mining pool through an election vote using a threshold. The contract contains several functions that are used in the removal process.

The propose-removal function is called by a miner to propose the removal of another miner from the pool. The function first checks that the miner who initiated the proposal is currently in the mining pool, that the miner to be removed is also in the mining pool, and that the miner to be removed has not already been proposed for removal. If all of these conditions are met, the function adds the miner to be removed to a list of proposed removals.

Once a miner has been proposed for removal, other miners can vote on whether or not to remove them from the pool using the vote-positive-remove-request and vote-negative-remove-request functions. These functions check that the voter is not the miner being voted on, that the miner being voted on has been proposed for removal, and that the voter has not already voted. If these conditions are met, the function adds the vote to either the map-votes-accept-removal or map-votes-reject-removal map, depending on whether the vote is positive or negative.

The process-removal function is called once the threshold of positive votes is reached. This function removes the miner from the mining pool, updates the miners-list variable, and deletes the miner's entry in the map-is-miner map. The function also adds the miner to a blacklist to prevent them from rejoining the pool in the future. If the removal of the miner causes the new percentage of miners to fall below a critical threshold, the update-threshold function is called to adjust the threshold accordingly.

If N - threshold negative votes for the removal action are reached, the reject-removal function is called. This function simply clears the votes for the miner and does not remove them from the pool.

There are several other helper functions in the contract, such as has-voted-remove, which checks if a miner has already voted, and clear-votes-map-remove-vote, which clears all votes for a specific miner. These functions are used throughout the contract to help manage the removal process.

Smart Contract

;; data stored
(define-constant err-not-in-miner-map (err u104))
(define-constant err-not-in-miner-map-miner-to-remove (err u114))
(define-constant err-already-proposed-for-removal (err u116))
(define-constant err-not-proposed-for-removal (err u117))
(define-constant err-cant-vote-himself (err u119))
(define-constant err-cant-remove-when-alone-in-pool (err u128))
(define-constant err-not-proposed-for-removal-k-missing (err u122))
(define-constant err-no-vote-permission (err u105))
(define-constant err-already-voted (err u108))

(define-map map-is-miner { address: principal } { value: bool })
(define-map map-block-proposed-to-remove { address: principal } { value: uint })
(define-map map-is-proposed-for-removal { address: principal } { value: bool })
(define-map map-remove-request-voter { miner-to-vote: principal, voter: principal } { value: bool })
(define-map map-votes-accept-removal { address: principal } { value: uint })
(define-map map-votes-reject-removal { address: principal } { value: uint })
(define-map map-blacklist { address: principal } { value: bool })

(define-data-var k uint u0)
(define-data-var n uint u1)


;; functions
(define-public (propose-removal (miner-to-remove principal))
(begin 
  (asserts! (not (is-eq (var-get n) u1)) err-cant-remove-when-alone-in-pool)
  (asserts! (check-is-miner-now tx-sender) err-not-in-miner-map) 
  (asserts! (check-is-miner-now miner-to-remove) err-not-in-miner-map-miner-to-remove)
  (asserts! (not (check-is-proposed-for-removal-now miner-to-remove)) err-already-proposed-for-removal) 
  (map-set map-block-proposed-to-remove {address: miner-to-remove} {value: block-height})
  (map-set map-is-proposed-for-removal {address: miner-to-remove} {value: true})
  (ok true)))

(define-public (vote-positive-remove-request (miner-to-vote principal))
(begin
  (asserts! (not (is-eq tx-sender miner-to-vote)) err-cant-vote-himself)
  (asserts! (check-is-proposed-for-removal-now miner-to-vote) err-not-proposed-for-removal) ;; map_is_proposed_for_removal
  (asserts! (is-ok (get-k-at-block-proposed-removal miner-to-vote)) err-not-proposed-for-removal-k-missing)
    (asserts! (unwrap! (check-is-miner-when-requested-remove miner-to-vote) err-cant-unwrap-check-miner) err-no-vote-permission)
    (asserts! (has-voted-remove miner-to-vote) err-already-voted) ;; O(1)
    (map-set map-remove-request-voter 
      {miner-to-vote: miner-to-vote, voter: tx-sender} 
      {value: true})
    (if (is-some (get value (map-get? map-votes-accept-removal {address: miner-to-vote}))) 
      (map-set map-votes-accept-removal {address: miner-to-vote} {value: (+ (unwrap-panic (get value (map-get? map-votes-accept-removal  {address: miner-to-vote}))) u1)})
      (map-set map-votes-accept-removal {address: miner-to-vote} {value: u1}))
    (some
      (if (is-vote-accepted (unwrap-panic (get value (map-get? map-votes-accept-removal {address: miner-to-vote}))) (unwrap-panic (get-k-at-block-proposed-removal miner-to-vote)))
        (process-removal miner-to-vote)
        (ok false)))
    (ok true)))

(define-public (vote-negative-remove-request (miner-to-vote principal))
(begin
  (asserts! (not (is-eq tx-sender miner-to-vote)) err-cant-vote-himself)
  (asserts! (check-is-proposed-for-removal-now miner-to-vote) err-not-proposed-for-removal) ;; map_is_waiting
  (asserts! (is-ok (get-k-at-block-proposed-removal miner-to-vote)) err-not-proposed-for-removal-k-missing)
  (asserts! (unwrap! (check-is-miner-when-requested-remove miner-to-vote) err-cant-unwrap-check-miner) err-no-vote-permission)
  (asserts! (has-voted-remove miner-to-vote) err-already-voted) ;; O(1)
  (map-set map-remove-request-voter 
    {miner-to-vote: miner-to-vote, voter: tx-sender} 
    {value: true})
  (if (is-some (get value (map-get? map-votes-reject-removal {address: miner-to-vote}))) 
    (map-set map-votes-reject-removal {address: miner-to-vote} {value: (+ (unwrap-panic (get value (map-get? map-votes-reject-removal {address: miner-to-vote}))) u1)})
    (map-set map-votes-reject-removal {address: miner-to-vote} {value: u1}))
  (some
    (if (is-vote-rejected-remove (unwrap-panic (get value (map-get? map-votes-reject-removal {address: miner-to-vote}))) (unwrap-panic (get-k-at-block-proposed-removal miner-to-vote)) (unwrap-panic (get-n-at-block-proposed-removal miner-to-vote)))
      (reject-removal miner-to-vote)
      (ok false)))
  (ok true)))

(define-private (process-removal (miner principal))
(begin 
  (let ((remove-result (unwrap-panic (remove-principal-miners-list miner)))
        (new-k-percentage (/ (* (var-get k) u100) (- (var-get n) u2))))
    (some (var-set miners-list remove-result))
    (var-set miner-to-remove-votes-remove miner)
    (var-set n (- (var-get n) u1))
    (map-delete map-is-miner {address: miner})
    (map-set map_blacklist {address: miner} {value: true})
    (clear-votes-map-remove-vote miner)
    (if (>= new-k-percentage (var-get k-critical)) 
      (update-threshold)
      false)
    (ok true))))

(define-private (reject-removal (miner principal))
(begin 
  (var-set miner-to-remove-votes-remove miner)
  (clear-votes-map-remove-vote miner)
  (ok true)))

(define-private (has-voted-remove (miner principal)) 
(not (if (is-some (get value (map-get? map-remove-request-voter {miner-to-vote: miner, voter: tx-sender})))
          (unwrap-panic (get value (map-get? map-remove-request-voter {miner-to-vote: miner, voter: tx-sender})))
          false
  )))

(define-private (clear-votes-map-remove-vote (miner principal)) 
(begin 
  (map-delete map-votes-accept-removal {address: (var-get miner-to-remove-votes-remove)})
  (map-delete map-votes-reject-removal {address: (var-get miner-to-remove-votes-remove)})
  (map-delete map-block-proposed-to-remove {address: (var-get miner-to-remove-votes-remove)})
  (map-delete map-is-proposed-for-removal {address: (var-get miner-to-remove-votes-remove)})
  (map remove-map-record-remove-vote (var-get miners-list))))

(define-private (remove-map-record-remove-vote (miner principal))
(if (is-some (map-get? map-remove-request-voter {miner-to-vote: (var-get miner-to-remove-votes-remove), voter: miner}))
  (map-delete map-remove-request-voter {miner-to-vote: (var-get miner-to-remove-votes-remove), voter: miner})
  false))

(define-private (get-k-at-block-proposed-removal (miner-to-vote principal)) 
(begin 
  (asserts! (is-some (get value (map-get? map-block-proposed-to-remove {address: miner-to-vote}))) err-not-proposed-for-removal)
  (at-block 
    (unwrap-panic 
      (get-block-info? id-header-hash 
        (unwrap-panic 
          (get value 
            (map-get? map-block-proposed-to-remove {address: miner-to-vote}))))) 
            (ok (var-get k)))))

(define-private (get-n-at-block-proposed-removal (miner-to-vote principal)) 
(begin 
  (asserts! (is-some (get value (map-get? map-block-proposed-to-remove {address: miner-to-vote}))) err-not-proposed-for-removal)
  (at-block 
    (unwrap-panic 
      (get-block-info? id-header-hash 
        (unwrap-panic 
          (get value 
            (map-get? map-block-proposed-to-remove {address: miner-to-vote}))))) 
            (ok (var-get n)))))

Last updated