private async Task Run(ulong blockNumber, CancellationToken stoppingToken) { void OnHealthCheck() { stoppingToken.ThrowIfCancellationRequested(); _application.Dispose(); } try { _application?.HealthCheck(TimeSpan.FromMinutes(1), OnHealthCheck); var blockHash = _application !.Application ! .GetBlockHash(new GetBlockHashParams() { BlockNumber = blockNumber }).Hash; _application.HealthCheck(TimeSpan.FromMinutes(1), OnHealthCheck); var block = _application.Application.GetBlock(new GetBlockParams() { BlockHash = blockHash }); _application.HealthCheck(TimeSpan.FromMinutes(1), OnHealthCheck); var eventsString = _application.Application.StorageApi.GetStorage("System", "Events", new GetBlockHashParams() { BlockNumber = blockNumber }); _application.CancelHealthCheck(); var eventsList = _application.Application.Serializer.Deserialize <EventList>(eventsString.HexToByteArray()); var extrinsics = block.Block.Extrinsic .Select(e => e !.HexToByteArray()) .Select(e => _application.Application.Serializer.DeserializeAssertReadAll <DeserializedExtrinsic>(e)) .Where((_, index) => eventsList.ExtrinsicSuccess((uint)index)) .ToList(); var actions = ProcessExtrinsics(extrinsics, blockNumber, stoppingToken).ToList(); stoppingToken.ThrowIfCancellationRequested(); await SaveToDatabase(blockNumber, stoppingToken, actions); } catch (JrpcErrorException ex) when(ex.Code == -32603) { await SaveToDatabase(blockNumber, stoppingToken, Array.Empty <ExtrinsicHandler>()); } }
public static Task CallSubstrate(this BackgroundService service, ILogger logger, PublicKey contractKey, string nodeEndpoint, Address from, byte[] privateKey, Func <IApplication, IExtrinsicCall> callGenerator) { var completionSource = new TaskCompletionSource(); Task.Run(async() => { SafeApplication application = SafeApplication.CreateApplication( ex => { logger.LogError(ex, "{ServiceName} substrate api failed", service.GetType().FullName); Interlocked.Exchange <TaskCompletionSource?>(ref completionSource, null)?.SetException(ex); }, logger, contractKey); try { application.Application.Connect(nodeEndpoint); var call = callGenerator(application.Application !); application.HealthCheck(TimeSpan.FromMinutes(10), () => { Interlocked.Exchange <TaskCompletionSource?>(ref completionSource, null)?.SetException(new TimeoutException()); application.Dispose(); }); var result = await application.Application.SignWaitRetryOnLowPriority(from, privateKey, call); application.CancelHealthCheck(); result.Switch(_ => { Interlocked.Exchange <TaskCompletionSource?>(ref completionSource, null)?.SetResult(); }, fail => { var error = fail.ErrorMessage(application.Application); logger.LogError("Failed to call substrate, {ErrorText}", error); Interlocked.Exchange <TaskCompletionSource?>(ref completionSource, null)?.SetException(new ApplicationException(error)); }); } catch (Exception ex) { Interlocked.Exchange <TaskCompletionSource?>(ref completionSource, null)?.SetException(ex); } finally { application.Dispose(); } }); return(completionSource.Task); }