# Add new miner

### Diagram flow

<figure><img src="/files/9vFSyGnZZY8EtyKE5vCu" alt=""><figcaption></figcaption></figure>

### Explanations

When a new miner wants to join the mining pool, they first need to call the `ask-to-join` function and provide their BTC address as a parameter. This function performs some checks to make sure that the miner is not already in the pool or in the waiting list, and then adds the miner to the waiting list by setting their `map-is-waiting` value to true and adding their address to the `waiting-list` variable.

Other miners in the pool can then vote on whether to accept or reject the new miner. To vote positively, they need to call the `vote-positive-join-request` function and provide the address of the miner they want to vote on as a parameter. Similarly, to vote negatively, they call the `vote-negative-join-request` function. These functions first check whether the miner being voted on is actually in the waiting list and whether the voter has already voted on this miner. If all checks pass, the voter's vote is recorded in the appropriate `map-votes-accept-join` or `map-votes-reject-join` map.

When the total number of positive votes for a miner reaches the threshold (which is integer of (N \* 67%) where N is the total number of miners), the miner is accepted into the mining pool. The `try-enter-pool` function is called by the miner being voted on to check if the threshold has been met. If it has, the miner is removed from the waiting list, added to the `pending-list` variable, and their `map-is-waiting` value is set to false. If the threshold has not been met, the function returns false.

Then, after 100 blocks have passed from the last time new miners were added to the pool, anyone can call the `add-pending-miners-to-pool` function, which adds all the pending miners to the mining pool. This is done to have less distributed key generations (DKG) and helps greatly in the mining alogirtm which takes into account `the average amount spent by a Bitcoin address in the last  6 blocks`. Using DKG the address will be totally different ( as the public key and private key are different as well ). So this process should not be done too often because the first 4 blocks after a DKG would mean very low changes at winning them, but still the need to invest the same amount as before. &#x20;

Once the miners are added to the pool, the threshold for actions is recalculated, and mining can continue with the new set of miners.

### Smart Contract

```lisp
;; data stored
(define-constant err-already-joined (err u101))
(define-constant err-already-asked-to-join (err u102))
(define-constant err-not-asked-to-join (err u103))
(define-constant err-no-vote-permission (err u104))
(define-constant err-already-voted (err u105))
(define-constant err-list-length-exceeded (err u106))
(define-constant err-no-pending-miners (err u107))
(define-constant err-more-blocks-to-pass (err u108))

(define-map map-is-miner { address: principal } { value: bool })
(define-map map-block-joined { address: principal } { block-height: uint })
(define-map map-block-asked-to-join { address: principal } { value: uint })
(define-map map-is-waiting { address: principal } { value: bool })
(define-map map-votes-accept-join { address: principal } { value: uint })
(define-map map-votes-reject-join { address: principal } { value: uint })
(define-map map-join-request-voter { miner-to-vote: principal, voter: principal } { value: bool })

(define-data-var k uint u0)
(define-data-var n uint u1)
(define-data-var waiting-list (list 100 principal) (list ))
(define-data-var miners-list (list 100 principal) (list ))
(define-data-var pending-accept-list (list 100 principal) (list ))
(define-data-var last-join-done uint u1)
(define-data-var k-percentage uint u67)
(define-data-var miner-to-remove-votes-join principal tx-sender)
(define-data-var blocks-to-pass uint u100)


;; functions
(define-public (ask-to-join (btc-address principal))
(begin 
  (asserts! (not (check-is-miner-now tx-sender)) err-already-joined) 
  (asserts! (not (check-is-waiting-now tx-sender)) err-already-asked-to-join) 
  (map-set map-block-asked-to-join {address: tx-sender} {value: block-height})
  (var-set waiting-list (unwrap-panic (as-max-len? (concat (var-get waiting-list) (list tx-sender)) u100)))
  (map-set map-is-waiting {address: tx-sender} {value: true})
  (ok true)))

(define-public (vote-positive-join-request (miner-to-vote principal))
(begin
  (asserts! (check-is-waiting-now miner-to-vote) err-not-asked-to-join) ;; map_is_waiting
    (asserts! (unwrap! (check-is-miner-when-requested-join miner-to-vote) err-cant-unwrap-check-miner) err-no-vote-permission)
    (asserts! (has-voted-join miner-to-vote) err-already-voted) ;; O(1)
    (map-set map-join-request-voter 
      {miner-to-vote: miner-to-vote, voter: tx-sender} 
      {value: true})
    (if (is-some (get value (map-get? map-votes-accept-join {address: miner-to-vote}))) 
      (map-set map-votes-accept-join {address: miner-to-vote} {value: (+ (unwrap-panic (get value (map-get? map-votes-accept-join {address: miner-to-vote}))) u1)})
      (map-set map-votes-accept-join {address: miner-to-vote} {value: u1}))
    (ok true)))

(define-public (vote-negative-join-request (miner-to-vote principal))
(begin
  (asserts! (check-is-waiting-now miner-to-vote) err-not-asked-to-join)
    (asserts! (unwrap! (check-is-miner-when-requested-join miner-to-vote) err-cant-unwrap-check-miner) err-no-vote-permission)
    (asserts! (has-voted-join miner-to-vote) err-already-voted)    
    (map-set map-join-request-voter 
      {miner-to-vote: miner-to-vote, voter: tx-sender} 
      {value: true})
    (if (is-some (get value (map-get? map-votes-reject-join {address: miner-to-vote}))) 
      (map-set map-votes-reject-join {address: miner-to-vote} {value: (+ (unwrap-panic (get value (map-get? map-votes-reject-join {address: miner-to-vote}))) u1)})
      (map-set map-votes-reject-join {address: miner-to-vote} {value: u1}))  
    (some
      (if (is-vote-rejected-join (unwrap-panic (get value (map-get? map-votes-reject-join {address: miner-to-vote}))) (unwrap-panic (get-k-at-block-asked-to-join miner-to-vote)) (unwrap-panic (get-n-at-block-asked-to-join miner-to-vote)))
        (reject-miner-in-pool miner-to-vote) 
        false))
    (ok true)))

(define-private (accept-miner-in-pool (miner principal)) 
(begin 
  (let ((pending-accept-result (as-max-len? (concat (var-get pending-accept-list) (list miner)) u100)))
  (asserts! (is-some pending-accept-result) err-list-length-exceeded) ;; O(1) 
  (var-set miner-to-remove-votes-join miner)
  (var-set waiting-list (unwrap-panic (as-max-len? (unwrap-panic (remove-principal-waiting-list miner)) u100))) ;; O(N)
  (map-delete map-is-waiting {address: miner})
  (clear-votes-map-join-vote miner)
  (ok (var-set pending-accept-list (unwrap-panic pending-accept-result))))))

(define-private (reject-miner-in-pool (miner principal)) 
(begin 
  (let ((remove-result (unwrap-panic (remove-principal-waiting-list miner))))
    (var-set miner-to-remove-votes-join miner)
    (var-set waiting-list remove-result)
    (map-delete map-is-waiting {address: miner})
    (clear-votes-map-join-vote miner)
    true)))

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

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

(define-private (is-in-voters-list (miner principal) (voters-list (list 100 principal))) 
(is-some (index-of voters-list miner)))

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

(define-public (try-enter-pool)
(begin 
  (asserts! (is-some (get value (map-get? map-votes-accept-join {address: tx-sender}))) err-not-asked-to-join)
  (if (is-vote-accepted (unwrap-panic (get value (map-get? map-votes-accept-join {address: tx-sender}))) (unwrap-panic (get-k-at-block-asked-to-join tx-sender)))
    (accept-miner-in-pool tx-sender) 
    (ok false))))

(define-public (add-pending-miners-to-pool) 
(begin
  (let ((len-pending-accept-list (len (var-get pending-accept-list))))
    (asserts! (not (is-eq len-pending-accept-list u0)) err-no-pending-miners)
    (asserts! (x-blocks-passed (var-get blocks-to-pass)) err-more-blocks-to-pass)
    (map add-miner-to-pool (var-get pending-accept-list))
    (asserts! (is-some (as-max-len? (concat (var-get miners-list) (var-get pending-accept-list)) u100)) err-list-length-exceeded)
    (var-set miners-list (unwrap-panic (as-max-len? (concat (var-get miners-list) (var-get pending-accept-list)) u100)))
    (var-set n (+ (var-get n) len-pending-accept-list))
    (var-set pending-accept-list (list ))
    (var-set last-join-done block-height)
    (some (update-threshold))
    (ok true))))

(define-private (update-threshold) 
(var-set k (/ (* (var-get k-percentage) (- (var-get n) u1)) u100)))

(define-public (add-miner-to-pool (miner principal))
(begin 
  (map-set map-is-miner {address: miner} {value: true})
  (map-set map-block-joined {address: miner} {block-height: block-height})
  (ok true)))

(define-private (x-blocks-passed (x uint)) 
(if (>= (- block-height (var-get last-join-done)) x)
  true
  false))

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

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.degenlab.io/decentralized-mining-pool/smart-contract/election-system/add-new-miner.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
