Skip to content

Commit

Permalink
Merge pull request #511 from iotaledger/slot-index-reward-param
Browse files Browse the repository at this point in the history
Accept `slotIndex` query param in rewards API
  • Loading branch information
PhilippGackstatter authored Nov 10, 2023
2 parents ac23b39 + 662e548 commit f381ddb
Showing 1 changed file with 28 additions and 6 deletions.
34 changes: 28 additions & 6 deletions components/restapi/core/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,23 @@ func rewardsByOutputID(c echo.Context) (*apimodels.ManaRewardsResponse, error) {
return nil, ierrors.Wrapf(err, "failed to parse output ID %s", c.Param(restapipkg.ParameterOutputID))
}

var slotIndex iotago.SlotIndex
if len(c.QueryParam(restapipkg.ParameterSlotIndex)) > 0 {
var err error
slotIndex, err = httpserver.ParseSlotQueryParam(c, restapipkg.ParameterSlotIndex)
if err != nil {
return nil, ierrors.Wrapf(err, "failed to parse slot index %s", c.Param(restapipkg.ParameterSlotIndex))
}
genesisSlot := deps.Protocol.LatestAPI().ProtocolParameters().GenesisSlot()
if slotIndex < genesisSlot {
return nil, ierrors.Wrapf(echo.ErrBadRequest, "slot index (%d) before genesis slot (%d)", slotIndex, genesisSlot)
}
} else {
// The slot index may be unset for requests that do not want to issue a transaction, such as displaying estimated rewards,
// in which case we use latest committed slot.
slotIndex = deps.Protocol.MainEngineInstance().SyncManager.LatestCommitment().Slot()
}

utxoOutput, err := deps.Protocol.MainEngineInstance().Ledger.Output(outputID)
if err != nil {
return nil, ierrors.Wrapf(echo.ErrInternalServerError, "failed to get output %s from ledger: %s", outputID.ToHex(), err)
Expand Down Expand Up @@ -164,17 +181,22 @@ func rewardsByOutputID(c echo.Context) (*apimodels.ManaRewardsResponse, error) {
case iotago.OutputDelegation:
//nolint:forcetypeassert
delegationOutput := utxoOutput.Output().(*iotago.DelegationOutput)
latestCommittedSlot := deps.Protocol.MainEngineInstance().SyncManager.LatestCommitment().Slot()
stakingEnd := delegationOutput.EndEpoch
// the output is in delayed calaiming state if endEpoch is set, otherwise we use latest possible epoch
if delegationOutput.EndEpoch == 0 {
stakingEnd = deps.Protocol.APIForSlot(latestCommittedSlot).TimeProvider().EpochFromSlot(deps.Protocol.MainEngineInstance().SyncManager.LatestCommitment().Slot())
delegationEnd := delegationOutput.EndEpoch
// If Delegation ID is zeroed, the output is in delegating state, which means its End Epoch is not set and we must use the
// "last epoch" for the rewards calculation.
// In this case the calculation must be consistent with the rewards calculation at execution time, so a client can specify
// a slot index explicitly, which should be equal to the slot it uses as the commitment input for the claiming transaction.
if delegationOutput.DelegationID.Empty() {
apiForSlot := deps.Protocol.APIForSlot(slotIndex)
futureBoundedSlotIndex := slotIndex + apiForSlot.ProtocolParameters().MinCommittableAge()
delegationEnd = apiForSlot.TimeProvider().EpochFromSlot(futureBoundedSlotIndex) - iotago.EpochIndex(1)
}

reward, actualStart, actualEnd, err = deps.Protocol.MainEngineInstance().SybilProtection.DelegatorReward(
delegationOutput.ValidatorAddress.AccountID(),
delegationOutput.DelegatedAmount,
delegationOutput.StartEpoch,
stakingEnd,
delegationEnd,
)
}
if err != nil {
Expand Down

0 comments on commit f381ddb

Please sign in to comment.