diff --git a/nym-validator-rewarder/migrations/01_initial.sql b/nym-validator-rewarder/migrations/01_initial.sql index b7b7b9f22f..2dbfb40e35 100644 --- a/nym-validator-rewarder/migrations/01_initial.sql +++ b/nym-validator-rewarder/migrations/01_initial.sql @@ -27,6 +27,7 @@ CREATE TABLE block_signing_reward rewarding_epoch_id INTEGER NOT NULL REFERENCES rewarding_epoch (id), validator_consensus_address TEXT NOT NULL, operator_account TEXT NOT NULL, + whitelisted BOOLEAN NOT NULL, amount TEXT NOT NULL, voting_power BIGINT NOT NULL, voting_power_share TEXT NOT NULL, @@ -38,11 +39,11 @@ CREATE TABLE block_signing_reward CREATE TABLE epoch_credential_issuance ( - rewarding_epoch_id INTEGER NOT NULL PRIMARY KEY REFERENCES rewarding_epoch (id), - starting_dkg_epoch INTEGER NOT NULL, - ending_dkg_epoch INTEGER NOT NULL, + rewarding_epoch_id INTEGER NOT NULL PRIMARY KEY REFERENCES rewarding_epoch (id), + starting_dkg_epoch INTEGER NOT NULL, + ending_dkg_epoch INTEGER NOT NULL, total_issued_partial_credentials INTEGER NOT NULL, - budget TEXT NOT NULL + budget TEXT NOT NULL ); CREATE TABLE malformed_credential @@ -56,6 +57,7 @@ CREATE TABLE credential_issuance_reward rewarding_epoch_id INTEGER NOT NULL REFERENCES rewarding_epoch (id), operator_account TEXT NOT NULL, amount TEXT NOT NULL, + whitelisted BOOLEAN NOT NULL, api_endpoint TEXT NOT NULL, issued_partial_credentials INTEGER NOT NULL, issued_credentials_share TEXT NOT NULL, diff --git a/nym-validator-rewarder/src/config/mod.rs b/nym-validator-rewarder/src/config/mod.rs index 9003d32ceb..49571394ad 100644 --- a/nym-validator-rewarder/src/config/mod.rs +++ b/nym-validator-rewarder/src/config/mod.rs @@ -9,7 +9,7 @@ use nym_config::{ must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR, }; -use nym_validator_client::nyxd::Coin; +use nym_validator_client::nyxd::{AccountId, Coin}; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DisplayFromStr}; use std::io; @@ -225,7 +225,7 @@ impl Default for RewardingRatios { impl RewardingRatios { pub fn ensure_is_valid(&self) -> Result<(), NymRewarderError> { if self.block_signing + self.credential_verification + self.credential_issuance != 1.0 { - todo!() + return Err(NymRewarderError::InvalidRewardingRatios { ratios: *self }); } Ok(()) } @@ -238,19 +238,26 @@ pub struct NyxdScraper { // TODO: debug with everything that's currently hardcoded in the scraper } -#[derive(Debug, Clone, Deserialize, Serialize, Copy)] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct BlockSigning { /// Specifies whether credential issuance for block signing is enabled. pub enabled: bool, + + /// List of validators that will receive rewards for block signing. + /// If not on the list, the validator will be treated as if it had 0 voting power. + pub whitelist: Vec, } impl Default for BlockSigning { fn default() -> Self { - BlockSigning { enabled: true } + BlockSigning { + enabled: true, + whitelist: vec![], + } } } -#[derive(Debug, Clone, Deserialize, Serialize, Copy)] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct IssuanceMonitor { /// Specifies whether credential issuance monitoring (and associated rewards) are enabled. pub enabled: bool, @@ -264,15 +271,20 @@ pub struct IssuanceMonitor { /// The sampling rate of the issued credentials pub sampling_rate: f64, + + /// List of validators that will receive rewards for credential issuance. + /// If not on the list, the validator will be treated as if it hadn't issued a single credential. + pub whitelist: Vec, } impl Default for IssuanceMonitor { fn default() -> Self { IssuanceMonitor { - enabled: true, + enabled: false, run_interval: DEFAULT_MONITOR_RUN_INTERVAL, min_validate_per_issuer: DEFAULT_MONITOR_MIN_VALIDATE, sampling_rate: DEFAULT_MONITOR_SAMPLING_RATE, + whitelist: vec![], } } } diff --git a/nym-validator-rewarder/src/config/template.rs b/nym-validator-rewarder/src/config/template.rs index 17ba1f9649..89eb22b933 100644 --- a/nym-validator-rewarder/src/config/template.rs +++ b/nym-validator-rewarder/src/config/template.rs @@ -40,7 +40,14 @@ credential_verification = {{ rewarding.ratios.credential_verification }} [block_signing] # Specifies whether credential issuance for block signing is enabled. enabled = {{ block_signing.enabled }} - + +# List of validators that will receive rewards for block signing. +# If not on the list, the validator will be treated as if it had 0 voting power. +whitelist = [ + # needs to be manually populated; expects nvalcons1... addresses. + # you can get them from, for example, `/cosmos/base/tendermint/v1beta1/validatorsets/latest` endpoint +] + [issuance_monitor] # Specifies whether credential issuance monitoring (and associated rewards) are enabled. @@ -54,6 +61,12 @@ min_validate_per_issuer = {{ issuance_monitor.min_validate_per_issuer }} # The sampling rate of the issued credentials sampling_rate = {{ issuance_monitor.sampling_rate }} + +# List of validators that will receive rewards for credential issuance. +# If not on the list, the validator will be treated as if it hadn't issued a single credential. +whitelist = [ + # needs to be manually populated; expects n1... addresses +] [nyxd_scraper] # Url to the websocket endpoint of a validator, for example `wss://rpc.nymtech.net/websocket` diff --git a/nym-validator-rewarder/src/error.rs b/nym-validator-rewarder/src/error.rs index b6dae63537..3d00f0324d 100644 --- a/nym-validator-rewarder/src/error.rs +++ b/nym-validator-rewarder/src/error.rs @@ -1,6 +1,7 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only +use crate::config::RewardingRatios; use nym_coconut::CoconutError; use nym_validator_client::nym_api::error::NymAPIError; use nym_validator_client::nyxd::error::NyxdError; @@ -50,7 +51,7 @@ pub enum NymRewarderError { NyxdFailure(#[from] NyxdError), #[error("the provided rewarding ratios don't add up to 1. ratios: {ratios:?}")] - InvalidRewardingRatios { ratios: Vec }, + InvalidRewardingRatios { ratios: RewardingRatios }, #[error("chain scraping failure: {source}")] ScraperFailure { @@ -156,6 +157,12 @@ pub enum NymRewarderError { #[error("the scraper websocket endpoint hasn't been provided")] UnavailableWebsocketUrl, + + #[error("block signing rewarding is enabled, but the validator whitelist is empty")] + EmptyBlockSigningWhitelist, + + #[error("credential issuance rewarding is enabled, but the validator whitelist is empty")] + EmptyCredentialIssuanceWhitelist, } #[derive(Debug)] diff --git a/nym-validator-rewarder/src/main.rs b/nym-validator-rewarder/src/main.rs index fb03008a9a..eb513124d1 100644 --- a/nym-validator-rewarder/src/main.rs +++ b/nym-validator-rewarder/src/main.rs @@ -1,8 +1,10 @@ -// Copyright 2023 - Nym Technologies SA +// Copyright 2023-2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only #![warn(clippy::expect_used)] #![warn(clippy::unwrap_used)] +#![warn(clippy::todo)] +#![warn(clippy::dbg_macro)] use crate::cli::Cli; use clap::{crate_name, crate_version, Parser}; diff --git a/nym-validator-rewarder/src/rewarder/block_signing/mod.rs b/nym-validator-rewarder/src/rewarder/block_signing/mod.rs index 4fcc75bc66..b87c6efaef 100644 --- a/nym-validator-rewarder/src/rewarder/block_signing/mod.rs +++ b/nym-validator-rewarder/src/rewarder/block_signing/mod.rs @@ -6,18 +6,19 @@ use crate::rewarder::block_signing::types::{EpochSigningResults, RawValidatorRes use crate::rewarder::epoch::Epoch; use crate::rewarder::nyxd_client::NyxdClient; use nym_validator_client::nyxd::module_traits::staking; -use nym_validator_client::nyxd::PageRequest; +use nym_validator_client::nyxd::{AccountId, PageRequest}; use nyxd_scraper::NyxdScraper; use std::cmp::min; use std::collections::HashMap; use std::ops::Range; -use tracing::info; +use tracing::{debug, info, warn}; pub(crate) mod types; pub struct EpochSigning { pub(crate) nyxd_client: NyxdClient, pub(crate) nyxd_scraper: NyxdScraper, + pub(crate) whitelist: Vec, } impl EpochSigning { @@ -116,14 +117,29 @@ impl EpochSigning { else { continue; }; - total_vp += vp; + + let cons_address = &validator.consensus_address; + // if this validator is NOT whitelisted, do not increase the total VP + let whitelisted = if let Ok(parsed) = cons_address.parse() { + if self.whitelist.contains(&parsed) { + debug!("{cons_address} is on the whitelist"); + total_vp += vp; + true + } else { + warn!("{cons_address} is not a valid consensus address"); + false + } + } else { + debug!("{cons_address} is not on the whitelist"); + false + }; let signed = self .nyxd_scraper .storage .get_signed_between_times(&validator.consensus_address, epoch_start, epoch_end) .await?; - signed_in_epoch.insert(validator, RawValidatorResult::new(signed, vp)); + signed_in_epoch.insert(validator, RawValidatorResult::new(signed, vp, whitelisted)); } let total = self diff --git a/nym-validator-rewarder/src/rewarder/block_signing/types.rs b/nym-validator-rewarder/src/rewarder/block_signing/types.rs index bd28b2f49d..8cf31a5ba5 100644 --- a/nym-validator-rewarder/src/rewarder/block_signing/types.rs +++ b/nym-validator-rewarder/src/rewarder/block_signing/types.rs @@ -15,6 +15,7 @@ pub struct ValidatorSigning { pub validator: models::Validator, pub staking_details: staking::Validator, pub operator_account: AccountId, + pub whitelisted: bool, pub voting_power_at_epoch_start: i64, pub voting_power_ratio: Decimal, @@ -33,6 +34,10 @@ impl ValidatorSigning { } pub fn reward_amount(&self, signing_budget: &Coin) -> Coin { + if !self.whitelisted { + return Coin::new(0, &signing_budget.denom); + } + let amount = Uint128::new(signing_budget.amount) * self.ratio_signed * self.voting_power_ratio; @@ -51,13 +56,15 @@ pub struct EpochSigningResults { pub struct RawValidatorResult { pub signed_blocks: i32, pub voting_power: i64, + pub whitelisted: bool, } impl RawValidatorResult { - pub fn new(signed_blocks: i32, voting_power: i64) -> Self { + pub fn new(signed_blocks: i32, voting_power: i64, whitelisted: bool) -> Self { Self { signed_blocks, voting_power, + whitelisted, } } } @@ -93,7 +100,11 @@ impl EpochSigningResults { let vp: u64 = raw_results.voting_power.try_into().unwrap_or_default(); let signed: u64 = raw_results.signed_blocks.try_into().unwrap_or_default(); - let voting_power_ratio = Decimal::from_ratio(vp, total_vp_u64); + let voting_power_ratio = if raw_results.whitelisted { + Decimal::from_ratio(vp, total_vp_u64) + } else { + Decimal::zero() + }; debug_assert!(signed <= blocks_u64); let ratio_signed = Decimal::from_ratio(signed, blocks_u64); @@ -110,6 +121,7 @@ impl EpochSigningResults { validator, staking_details, operator_account, + whitelisted: raw_results.whitelisted, voting_power_at_epoch_start: raw_results.voting_power, voting_power_ratio, signed_blocks: raw_results.signed_blocks, @@ -129,10 +141,11 @@ impl EpochSigningResults { .iter() .inspect(|v| { info!( - "validator {} will receive {} at address {} for block signing work", + "validator {} will receive {} at address {} for block signing work (whitelisted: {})", v.moniker(), v.reward_amount(budget), - v.operator_account + v.operator_account, + v.whitelisted ); }) .map(|v| (v.operator_account.clone(), vec![v.reward_amount(budget)])) diff --git a/nym-validator-rewarder/src/rewarder/credential_issuance/mod.rs b/nym-validator-rewarder/src/rewarder/credential_issuance/mod.rs index 5807a60dec..7102ac2e69 100644 --- a/nym-validator-rewarder/src/rewarder/credential_issuance/mod.rs +++ b/nym-validator-rewarder/src/rewarder/credential_issuance/mod.rs @@ -8,6 +8,7 @@ use crate::rewarder::credential_issuance::types::{CredentialIssuanceResults, Mon use crate::rewarder::epoch::Epoch; use crate::rewarder::nyxd_client::NyxdClient; use nym_task::TaskClient; +use nym_validator_client::nyxd::AccountId; use tracing::info; mod monitor; @@ -21,9 +22,11 @@ impl CredentialIssuance { pub(crate) async fn new( epoch: Epoch, nyxd_client: &NyxdClient, + whitelist: &[AccountId], ) -> Result { Ok(CredentialIssuance { - monitoring_results: MonitoringResults::new_initial(epoch, nyxd_client).await?, + monitoring_results: MonitoringResults::new_initial(epoch, nyxd_client, whitelist) + .await?, }) } diff --git a/nym-validator-rewarder/src/rewarder/credential_issuance/monitor.rs b/nym-validator-rewarder/src/rewarder/credential_issuance/monitor.rs index 884a63b9fe..96bdef6aae 100644 --- a/nym-validator-rewarder/src/rewarder/credential_issuance/monitor.rs +++ b/nym-validator-rewarder/src/rewarder/credential_issuance/monitor.rs @@ -235,12 +235,15 @@ impl CredentialIssuanceMonitor { let api_client = api_client(&issuer)?; let epoch_credentials = api_client.epoch_credentials(epoch_id).await?; + let whitelisted = self.config.whitelist.contains(&issuer.operator_account); + let Some(first_id) = epoch_credentials.first_epoch_credential_id else { // no point in doing anything more - if they haven't issued anything, there's nothing to verify debug!("no credentials issued this epoch",); return Ok(RawOperatorResult::new_empty( issuer.operator_account, issuer.api_runner, + whitelisted, )); }; trace!("issued credentials: {epoch_credentials:?}"); @@ -283,6 +286,7 @@ impl CredentialIssuanceMonitor { Ok(RawOperatorResult { operator_account: issuer.operator_account, api_runner: issuer.api_runner, + whitelisted, issued_credentials: epoch_credentials.total_issued, validated_credentials: sampled, }) diff --git a/nym-validator-rewarder/src/rewarder/credential_issuance/types.rs b/nym-validator-rewarder/src/rewarder/credential_issuance/types.rs index e6f76a10ae..4b84870f70 100644 --- a/nym-validator-rewarder/src/rewarder/credential_issuance/types.rs +++ b/nym-validator-rewarder/src/rewarder/credential_issuance/types.rs @@ -25,6 +25,7 @@ impl MonitoringResults { pub(crate) async fn new_initial( initial_epoch: Epoch, nyxd_client: &NyxdClient, + whitelist: &[AccountId], ) -> Result { let epoch = nyxd_client.dkg_epoch().await?; let issuers = nyxd_client.get_credential_issuers(epoch.epoch_id).await?; @@ -36,6 +37,7 @@ impl MonitoringResults { let mut raw_issuer = RawOperatorIssuing { api_runner: issuer.api_runner.clone(), runner_account: issuer.operator_account.clone(), + whitelisted: whitelist.contains(&issuer.operator_account), per_epoch: Default::default(), }; @@ -132,6 +134,7 @@ impl MonitoringResults { RawOperatorIssuing { api_runner: result.api_runner.clone(), runner_account: result.runner_account.clone(), + whitelisted: result.whitelisted, per_epoch: kept_epoch, }, ); @@ -157,18 +160,20 @@ pub(crate) struct MonitoringResultsInner { impl From for CredentialIssuanceResults { fn from(value: MonitoringResultsInner) -> Self { - let total_issued = value - .operators - .values() - .map(|o| { - let operator_issued: u32 = o + let mut total_issued = 0; + + for operator in value.operators.values() { + // if this validator is NOT whitelisted, do not increase the total issued credentials + if operator.whitelisted { + let operator_issued: u32 = operator .per_epoch .values() .map(|e| e.issued_since_monitor_started) .sum(); - operator_issued - }) - .sum(); + + total_issued += operator_issued + } + } CredentialIssuanceResults { total_issued_partial_credentials: total_issued, @@ -177,7 +182,7 @@ impl From for CredentialIssuanceResults { .operators .into_values() .map(|runner| { - let issued_ratio = if total_issued == 0 { + let issued_ratio = if total_issued == 0 || !runner.whitelisted { Decimal::zero() } else { Decimal::from_ratio(runner.issued_credentials(), total_issued) @@ -187,6 +192,7 @@ impl From for CredentialIssuanceResults { issued_credentials: runner.issued_credentials(), validated_credentials: runner.validated_credentials(), api_runner: runner.api_runner, + whitelisted: runner.whitelisted, runner_account: runner.runner_account, } }) @@ -212,6 +218,7 @@ impl MonitoringResultsInner { pub(crate) struct RawOperatorResult { pub(crate) operator_account: AccountId, pub(crate) api_runner: String, + pub(crate) whitelisted: bool, // how many credentials the operator claims to have issued in **TOTAL** in this **DKG** epoch pub(crate) issued_credentials: u32, @@ -219,10 +226,15 @@ pub(crate) struct RawOperatorResult { } impl RawOperatorResult { - pub(crate) fn new_empty(operator_account: AccountId, api_runner: String) -> RawOperatorResult { + pub(crate) fn new_empty( + operator_account: AccountId, + api_runner: String, + whitelisted: bool, + ) -> RawOperatorResult { RawOperatorResult { operator_account, api_runner, + whitelisted, issued_credentials: 0, validated_credentials: Default::default(), } @@ -232,6 +244,7 @@ impl RawOperatorResult { pub struct RawOperatorIssuing { pub api_runner: String, pub runner_account: AccountId, + pub whitelisted: bool, pub per_epoch: HashMap, } @@ -243,6 +256,7 @@ impl RawOperatorIssuing { RawOperatorIssuing { api_runner: raw_result.api_runner, runner_account: raw_result.operator_account, + whitelisted: raw_result.whitelisted, per_epoch, } } @@ -278,6 +292,7 @@ impl IssuedEpochCredentials { pub struct OperatorIssuing { pub api_runner: String, + pub whitelisted: bool, pub runner_account: AccountId, pub issued_ratio: Decimal, @@ -286,10 +301,14 @@ pub struct OperatorIssuing { } impl OperatorIssuing { - pub fn reward_amount(&self, signing_budget: &Coin) -> Coin { - let amount = Uint128::new(signing_budget.amount) * self.issued_ratio; + pub fn reward_amount(&self, issuance_budget: &Coin) -> Coin { + if !self.whitelisted { + return Coin::new(0, &issuance_budget.denom); + } - Coin::new(amount.u128(), &signing_budget.denom) + let amount = Uint128::new(issuance_budget.amount) * self.issued_ratio; + + Coin::new(amount.u128(), &issuance_budget.denom) } } @@ -305,10 +324,11 @@ impl CredentialIssuanceResults { .iter() .inspect(|a| { info!( - "operator {} will receive {} at address {} for credential issuance work", + "operator {} will receive {} at address {} for credential issuance work (whitelisted: {})", a.api_runner, a.reward_amount(budget), a.runner_account, + a.whitelisted ); }) .map(|v| (v.runner_account.clone(), vec![v.reward_amount(budget)])) diff --git a/nym-validator-rewarder/src/rewarder/mod.rs b/nym-validator-rewarder/src/rewarder/mod.rs index f58b3ce63f..f586167c09 100644 --- a/nym-validator-rewarder/src/rewarder/mod.rs +++ b/nym-validator-rewarder/src/rewarder/mod.rs @@ -41,17 +41,19 @@ impl EpochRewards { let mut amounts = Vec::new(); if let Some(signing) = &self.signing { - for signing_amount in signing.rewarding_amounts(&self.signing_budget) { - if signing_amount.1[0].amount != 0 { - amounts.push(signing_amount) + for (account, signing_amount) in signing.rewarding_amounts(&self.signing_budget) { + if signing_amount[0].amount != 0 { + amounts.push((account, signing_amount)) } } } if let Some(credentials) = &self.credentials { - for credential_amount in credentials.rewarding_amounts(&self.credentials_budget) { - if credential_amount.1[0].amount != 0 { - amounts.push(credential_amount) + for (account, credential_amount) in + credentials.rewarding_amounts(&self.credentials_budget) + { + if credential_amount[0].amount != 0 { + amounts.push((account, credential_amount)) } } } @@ -86,18 +88,29 @@ impl Rewarder { }; let epoch_signing = if config.block_signing.enabled { + let whitelist = config.block_signing.whitelist.clone(); + if whitelist.is_empty() { + return Err(NymRewarderError::EmptyBlockSigningWhitelist); + } + let nyxd_scraper = NyxdScraper::new(config.scraper_config()).await?; Some(EpochSigning { nyxd_scraper, nyxd_client: nyxd_client.clone(), + whitelist, }) } else { None }; let credential_issuance = if config.issuance_monitor.enabled { - Some(CredentialIssuance::new(current_epoch, &nyxd_client).await?) + let whitelist = &config.issuance_monitor.whitelist; + if whitelist.is_empty() { + return Err(NymRewarderError::EmptyCredentialIssuanceWhitelist); + } + + Some(CredentialIssuance::new(current_epoch, &nyxd_client, whitelist).await?) } else { None }; @@ -239,7 +252,7 @@ impl Rewarder { if let Some(ref credential_issuance) = self.credential_issuance { credential_issuance.start_monitor( - self.config.issuance_monitor, + self.config.issuance_monitor.clone(), self.nyxd_client.clone(), task_manager.subscribe(), ); diff --git a/nym-validator-rewarder/src/rewarder/storage/manager.rs b/nym-validator-rewarder/src/rewarder/storage/manager.rs index 5d5ab191f8..b8f84bbd18 100644 --- a/nym-validator-rewarder/src/rewarder/storage/manager.rs +++ b/nym-validator-rewarder/src/rewarder/storage/manager.rs @@ -74,6 +74,7 @@ impl StorageManager { epoch: i64, consensus_address: String, operator_account: String, + whitelisted: bool, amount: String, voting_power: i64, voting_power_share: String, @@ -86,16 +87,18 @@ impl StorageManager { rewarding_epoch_id, validator_consensus_address, operator_account, + whitelisted, amount, voting_power, voting_power_share, signed_blocks, signed_blocks_percent - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "#, epoch, consensus_address, operator_account, + whitelisted, amount, voting_power, voting_power_share, @@ -144,6 +147,7 @@ impl StorageManager { &self, epoch: i64, operator_account: String, + whitelisted: bool, amount: String, api_endpoint: String, issued_partial_credentials: u32, @@ -155,15 +159,17 @@ impl StorageManager { INSERT INTO credential_issuance_reward ( rewarding_epoch_id, operator_account, + whitelisted, amount, api_endpoint, issued_partial_credentials, issued_credentials_share, validated_issued_credentials - ) VALUES (?, ?, ?, ?, ?, ?, ?) + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) "#, epoch, operator_account, + whitelisted, amount, api_endpoint, issued_partial_credentials, diff --git a/nym-validator-rewarder/src/rewarder/storage/mod.rs b/nym-validator-rewarder/src/rewarder/storage/mod.rs index aada9ef5dd..0c35fb0400 100644 --- a/nym-validator-rewarder/src/rewarder/storage/mod.rs +++ b/nym-validator-rewarder/src/rewarder/storage/mod.rs @@ -104,6 +104,7 @@ impl RewarderStorage { epoch_id, validator.validator.consensus_address, validator.operator_account.to_string(), + validator.whitelisted, reward_amount, validator.voting_power_at_epoch_start, validator.voting_power_ratio.to_string(), @@ -152,6 +153,7 @@ impl RewarderStorage { .insert_rewarding_epoch_credential_issuance_reward( epoch_id, api_runner.runner_account.to_string(), + api_runner.whitelisted, reward_amount, api_runner.api_runner, api_runner.issued_credentials,