Keeper Selection

In order to introduce more advanced and optimized strategies of keeper selection, PowerAgent will be completed with different strategies of selection, the choice of which will be optional depending on the situation.

The most prioritized strategy by now is random keeper selection.

Sources of Random Numbers

One can simply take block.difficulty as a source for the random number to later use it to select a keeper. However, this number does not satisfy the condition of not being deterministic.

Other, more decentralized way is to query a pseudorandom number by RanDAO. RanDAO is a blockchain based verifiable random number generator, which provides a non-deterministic pseudo random number for any contracts’ disposal.

Keeper Assignment

In the updated contract, an EnumerableSet.UintSet internal activeKeepers will hold numerated keepers that are active and ready to be assigned to a Job.

A function assignNextKeeper(bytes32 jobKey) internal is responsible for choosing a random keeper from the set of active keepers and assigning it to the job with jobKey.

The main step is to randomly choose the keeper (by its index) from the set:

index = (_getPseudoRandom() + jobKey) % NumberOfKeepers

The function _getPseudoRandom() yields the pseudo random number by one of the underlying algorithms described above.

After that the keeper by the index is selected and undergoes trial for the job prerequisites.

Assertions

For the keeper to be successfully assigned, the following conditions must be met:

  • Keeper has sufficient stake for this Job.

  • Keeper must be active.

Otherwise, the index is increased by 1 and the next keeper from the set is checked until one satisfying the conditions is met.

Events

On successful keeper selection, the function will emit KeeperJobLock(nextExecutionKeeperId, jobKey).

The infromation on the Job's keeper that will perform the next execution and the keeper's jobs is stored in the mappings respectively:

  • mapping(bytes32 => uint256) public jobNextKeeperId

  • mapping(uint256 => EnumerableSet.Bytes32Set) internal keeperLocksByJob

When Called

The assignment function is called every time a new Job is registered, a Job config is changed, a Job is topped up with credits, and, of course, after each Job execution.

Keeper Release

The keeper is released from the job automatically after the job has been executed by this keeper, and the next keeper is assigned.

Also, a helper function releaseKeeperIfRequired(jobKey, expectedKeeperId) is called each time a Job owner changes the config or withdraws credits from the Job to prevent keepers from executing a task they will not receive payment for.

On special occasions the keeper can be released from the assigned job by the keeper themselves. This function may be needed when, for example, a keeper may decide to discontinue participation and withdraw their CVP stake.

The function releaseJob(uint256 keeperId_, bytes32 jobKey_) external is responsible for this. It can be called by the keeper admin contract.

The following requirements must be met:

  • The keeper is assigned to the job specified in the arguments.

  • For interval jobs, the next execution should not be awaited.

  • The keeper must not undergo slashing at the time of the release.

  • The job must not be resolver type.

If all met, the keeper is released from its duty.

Last updated