package attestationutil import ( "context" "sort" "github.com/pkg/errors" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/go-bitfield" "go.opencensus.io/trace" ) // ConvertToIndexed converts attestation to (almost) indexed-verifiable form. // // Note about spec pseudocode definition. The state was used by get_attesting_indices to determine // the attestation committee. Now that we provide this as an argument, we no longer need to provide // a state. // // Spec pseudocode definition: // def get_indexed_attestation(state: BeaconState, attestation: Attestation) -> IndexedAttestation: // """ // Return the indexed attestation corresponding to ``attestation``. // """ // attesting_indices = get_attesting_indices(state, attestation.data, attestation.aggregation_bits) // // return IndexedAttestation( // attesting_indices=sorted(attesting_indices), // data=attestation.data, // signature=attestation.signature, // ) func ConvertToIndexed(ctx context.Context, attestation *ethpb.Attestation, committee []uint64) (*ethpb.IndexedAttestation, error) { ctx, span := trace.StartSpan(ctx, "core.ConvertToIndexed") defer span.End() attIndices, err := AttestingIndices(attestation.AggregationBits, committee) if err != nil { return nil, errors.Wrap(err, "could not get attesting indices") } sort.Slice(attIndices, func(i, j int) bool { return attIndices[i] < attIndices[j] }) inAtt := ðpb.IndexedAttestation{ Data: attestation.Data, Signature: attestation.Signature, AttestingIndices: attIndices, } return inAtt, nil } // AttestingIndices returns the attesting participants indices from the attestation data. The // committee is provided as an argument rather than a direct implementation from the spec definition. // Having the committee as an argument allows for re-use of beacon committees when possible. // // Spec pseudocode definition: // def get_attesting_indices(state: BeaconState, // data: AttestationData, // bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]) -> Set[ValidatorIndex]: // """ // Return the set of attesting indices corresponding to ``data`` and ``bits``. // """ // committee = get_beacon_committee(state, data.slot, data.index) // return set(index for i, index in enumerate(committee) if bits[i]) func AttestingIndices(bf bitfield.Bitfield, committee []uint64) ([]uint64, error) { indices := make([]uint64, 0, len(committee)) indicesSet := make(map[uint64]bool, len(committee)) for i, idx := range committee { if !indicesSet[idx] { if bf.BitAt(uint64(i)) { indices = append(indices, idx) } } indicesSet[idx] = true } return indices, nil }