func MergeDuties(ctx context.Context, attesterDuties []*api.AttesterDuty) ([]*Duty, error) {
	duties := make([]*Duty, 0)
	if len(attesterDuties) == 0 {
		return duties, nil
	}
	validatorIndices := make(map[phase0.Slot][]phase0.ValidatorIndex)
	committeeIndices := make(map[phase0.Slot][]phase0.CommitteeIndex)
	validatorCommitteeIndices := make(map[phase0.Slot][]uint64)
	committeeLengths := make(map[phase0.Slot]map[phase0.CommitteeIndex]uint64)
	committeesAtSlots := make(map[phase0.Slot]uint64)
	arrayCap := uint64(len(attesterDuties))
	sort.Slice(attesterDuties, func(i int, j int) bool {
		if attesterDuties[i].Slot < attesterDuties[j].Slot {
			return true
		}
		if attesterDuties[i].Slot > attesterDuties[j].Slot {
			return false
		}
		if attesterDuties[i].CommitteeIndex < attesterDuties[j].CommitteeIndex {
			return true
		}
		if attesterDuties[i].CommitteeIndex > attesterDuties[j].CommitteeIndex {
			return false
		}
		return attesterDuties[i].ValidatorIndex < attesterDuties[j].ValidatorIndex
	})
	for _, duty := range attesterDuties {
		_, exists := validatorIndices[duty.Slot]
		if !exists {
			validatorIndices[duty.Slot] = make([]phase0.ValidatorIndex, 0, arrayCap)
			committeeIndices[duty.Slot] = make([]phase0.CommitteeIndex, 0, arrayCap)
			committeeLengths[duty.Slot] = make(map[phase0.CommitteeIndex]uint64)
			committeesAtSlots[duty.Slot] = duty.CommitteesAtSlot
		}
		committeesAtSlots[duty.Slot] = duty.CommitteesAtSlot
		validatorIndices[duty.Slot] = append(validatorIndices[duty.Slot], duty.ValidatorIndex)
		committeeIndices[duty.Slot] = append(committeeIndices[duty.Slot], duty.CommitteeIndex)
		committeeLengths[duty.Slot][duty.CommitteeIndex] = duty.CommitteeLength
		validatorCommitteeIndices[duty.Slot] = append(validatorCommitteeIndices[duty.Slot], duty.ValidatorCommitteeIndex)
	}
	for slot := range validatorIndices {
		if duty, err := NewDuty(
			ctx,
			slot,
			committeesAtSlots[slot],
			validatorIndices[slot],
			committeeIndices[slot],
			validatorCommitteeIndices[slot],
			committeeLengths[slot],
		); err == nil {
			duties = append(duties, duty)
		}
	}
	sort.Slice(duties, func(i int, j int) bool {
		if duties[i].Slot() < duties[j].Slot() {
			return true
		}
		if duties[i].Slot() > duties[j].Slot() {
			return false
		}
		return true
	})
	return duties, nil
}
MergeDuties merges attester duties given by an Ethereum 2 client into vouch's per-slot structure.
package attester
import (
	"context"
	"sort"
	api "github.com/attestantio/go-eth2-client/api/v1"
	"github.com/attestantio/go-eth2-client/spec/phase0"
)