public async Task ProcessAttestationDutiesAsync(Slot slot, CancellationToken cancellationToken) { // If attester, get attestation, sign attestation, return to node IList <(BlsPublicKey, CommitteeIndex)> attestationDutyList = _validatorState.GetAttestationDutyForSlot(slot); foreach ((BlsPublicKey validatorPublicKey, CommitteeIndex index) in attestationDutyList) { Activity activity = new Activity("process-attestation-duty"); activity.Start(); using IDisposable activityScope = _logger.BeginScope("[TraceId, {TraceId}], [SpanId, {SpanId}]", activity.TraceId, activity.SpanId); try { if (_logger.IsDebug()) { LogDebug.RequestingAttestationFor(_logger, slot, _beaconChainInformation.Time, validatorPublicKey, null); } ApiResponse <Attestation> newAttestationResponse = await _beaconNodeApi .NewAttestationAsync(validatorPublicKey, false, slot, index, cancellationToken) .ConfigureAwait(false); if (newAttestationResponse.StatusCode == StatusCode.Success) { Attestation unsignedAttestation = newAttestationResponse.Content; BlsSignature attestationSignature = await GetAttestationSignatureAsync(unsignedAttestation, validatorPublicKey) .ConfigureAwait(false); Attestation signedAttestation = new Attestation(unsignedAttestation.AggregationBits, unsignedAttestation.Data, attestationSignature); // TODO: Getting one attestation at a time probably isn't very scalable. // All validators are attesting the same data, just in different committees with different indexes // => Get the data once, group relevant validators by committee, sign and aggregate within each // committee (marking relevant aggregation bits), then publish one pre-aggregated value? if (_logger.IsDebug()) { LogDebug.PublishingSignedAttestation(_logger, slot, index, validatorPublicKey.ToShortString(), signedAttestation.Data, signedAttestation.Signature.ToString().Substring(0, 10), null); } ApiResponse publishAttestationResponse = await _beaconNodeApi .PublishAttestationAsync(signedAttestation, cancellationToken) .ConfigureAwait(false); if (publishAttestationResponse.StatusCode != StatusCode.Success && publishAttestationResponse.StatusCode != StatusCode.BroadcastButFailedValidation) { throw new Exception( $"Error response from publish: {(int) publishAttestationResponse.StatusCode} {publishAttestationResponse.StatusCode}."); } bool nodeAccepted = publishAttestationResponse.StatusCode == StatusCode.Success; // TODO: Log warning if not accepted? Not sure what else we could do. } } catch (Exception ex) { Log.ExceptionProcessingAttestationDuty(_logger, slot, validatorPublicKey, ex.Message, ex); } finally { activity.Stop(); } _validatorState.ClearAttestationDutyForSlot(slot); } }