Nethereum.BlockchainProcessing 5.8.0

Prefix Reserved
dotnet add package Nethereum.BlockchainProcessing --version 5.8.0
                    
NuGet\Install-Package Nethereum.BlockchainProcessing -Version 5.8.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Nethereum.BlockchainProcessing" Version="5.8.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nethereum.BlockchainProcessing" Version="5.8.0" />
                    
Directory.Packages.props
<PackageReference Include="Nethereum.BlockchainProcessing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Nethereum.BlockchainProcessing --version 5.8.0
                    
#r "nuget: Nethereum.BlockchainProcessing, 5.8.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Nethereum.BlockchainProcessing@5.8.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Nethereum.BlockchainProcessing&version=5.8.0
                    
Install as a Cake Addin
#tool nuget:?package=Nethereum.BlockchainProcessing&version=5.8.0
                    
Install as a Cake Tool

Nethereum.BlockchainProcessing

Nethereum.BlockchainProcessing provides a comprehensive framework for crawling, processing, and storing Ethereum blockchain data including blocks, transactions, receipts, and event logs with flexible filtering, progress tracking, and storage capabilities.

Overview

This package enables applications to:

  • Crawl blockchain data - Process blocks, transactions, receipts, and logs sequentially
  • Track progress - Resume processing from last processed block
  • Store data - Persist blockchain data to custom storage backends
  • Filter events - Process specific event types or contracts
  • Handle confirmations - Wait for block confirmations before processing
  • Batch process logs - Efficiently retrieve and process event logs in batches
  • Process ERC20/ERC721 - Built-in support for token event processing

Installation

dotnet add package Nethereum.BlockchainProcessing

Core Architecture

The package follows a modular pipeline architecture with clear separation of concerns:

BlockchainProcessor (executor)
  ├── IBlockchainProcessingOrchestrator (strategy)
  │   ├── BlockCrawlOrchestrator (block-by-block crawling)
  │   └── LogOrchestrator (batch log retrieval)
  ├── BlockProcessingSteps (pipeline stages)
  ├── IBlockProgressRepository (progress tracking)
  └── ILastConfirmedBlockNumberService (confirmation management)

Core Components

BlockchainProcessor

Main processor that manages continuous blockchain processing. Located in BlockchainProcessor.cs:12-121.

Key Methods:

  • ExecuteAsync(CancellationToken, BigInteger?) - Process until cancelled (Line 34)
  • ExecuteAsync(BigInteger toBlockNumber, ...) - Process to specific block (Line 66)

Features:

  • Progress tracking via IBlockProgressRepository
  • Automatic block confirmation handling
  • Cancellation token support
  • Resume from last processed block

BlockCrawlOrchestrator

Orchestrates crawling of blocks, transactions, receipts, and logs. Located in BlockProcessing/BlockCrawlOrchestrator.cs:10-113.

Processing Flow:

  1. Fetch BlockBlockCrawlerStep (Line 46)
  2. For Each Transaction:
    • Process Transaction → TransactionCrawlerStep (Line 62)
    • Fetch Receipt → TransactionReceiptCrawlerStep (Line 73)
    • Extract Contract Creation → ContractCreatedCrawlerStep (if applicable)
  3. For Each Log:
    • Process Log → FilterLogCrawlerStep (Line 103)

BlockProcessingSteps

Defines processing pipeline stages. Located in BlockProcessing/BlockProcessingSteps.cs:6-38.

Steps:

  • BlockStep - Processes BlockWithTransactions (Line 8)
  • TransactionStep - Processes TransactionVO (Line 9)
  • TransactionReceiptStep - Processes TransactionReceiptVO (Line 10)
  • FilterLogStep - Processes FilterLogVO (Line 11)
  • ContractCreationStep - Processes ContractCreationVO (Line 12)

Each step is a Processor<T> that can have multiple handlers.

Processor<T>

Generic processor that executes multiple handlers. Located in Processor/Processor.cs:9-71.

Key Features:

  • Multiple handlers per processor (Line 22)
  • Optional match criteria for filtering (Line 13)
  • Sequential handler execution (Line 43)
  • Synchronous and asynchronous handler support

Usage Examples

Example 1: Basic Block Processing

Process all blocks, transactions, and logs:

using Nethereum.BlockchainProcessing;
using Nethereum.Web3;
using System.Numerics;

var web3 = new Web3("https://mainnet.infura.io/v3/YOUR_KEY");

var processedData = new ProcessedData();

var blockProcessor = web3.Processing.Blocks.CreateBlockProcessor(steps =>
{
    // Process each block
    steps.BlockStep.AddSynchronousProcessorHandler(block =>
    {
        Console.WriteLine($"Block: {block.Number}");
        processedData.Blocks.Add(block);
    });

    // Process each transaction
    steps.TransactionStep.AddSynchronousProcessorHandler(tx =>
    {
        Console.WriteLine($"  Transaction: {tx.Transaction.TransactionHash}");
        processedData.Transactions.Add(tx);
    });

    // Process transaction receipts
    steps.TransactionReceiptStep.AddSynchronousProcessorHandler(tx =>
    {
        Console.WriteLine($"  Receipt - Gas Used: {tx.TransactionReceipt.GasUsed}");
        processedData.TransactionsWithReceipt.Add(tx);
    });

    // Process event logs
    steps.FilterLogStep.AddSynchronousProcessorHandler(filterLog =>
    {
        Console.WriteLine($"    Log: {filterLog.Log.Address}");
        processedData.FilterLogs.Add(filterLog);
    });
});

// Process blocks 100-110
await blockProcessor.ExecuteAsync(
    toBlockNumber: new BigInteger(110),
    cancellationToken: CancellationToken.None,
    startAtBlockNumberIfNotProcessed: new BigInteger(100)
);

From test: BlockProcessing/BlockProcessingTests.cs:17-44

Example 2: Processing with Progress Tracking

Resume processing from last processed block:

using Nethereum.BlockchainProcessing.ProgressRepositories;

var web3 = new Web3("https://mainnet.infura.io/v3/YOUR_KEY");

// Track progress (persists across runs)
var progressRepository = new InMemoryBlockchainProgressRepository(
    lastBlockProcessed: new BigInteger(1000)
);

var blockProcessor = web3.Processing.Blocks.CreateBlockProcessor(
    progressRepository,
    steps =>
    {
        steps.BlockStep.AddSynchronousProcessorHandler(block =>
        {
            Console.WriteLine($"Processing block: {block.Number}");
        });
    }
);

// Process continuously until cancelled
// Will start from block 1001 (last processed + 1)
var cancellationTokenSource = new CancellationTokenSource();

await blockProcessor.ExecuteAsync(cancellationTokenSource.Token);

// Progress is automatically saved after each block

From test: BlockProcessing/BlockProcessingTests.cs:164-195

Example 3: Block Confirmations

Wait for block confirmations before processing:

const uint MIN_CONFIRMATIONS = 12;

var progressRepository = new InMemoryBlockchainProgressRepository(
    lastBlockProcessed: new BigInteger(100)
);

var blockProcessor = web3.Processing.Blocks.CreateBlockProcessor(
    progressRepository,
    steps =>
    {
        steps.BlockStep.AddSynchronousProcessorHandler(block =>
        {
            Console.WriteLine($"Processing confirmed block: {block.Number}");
        });
    },
    minimumBlockConfirmations: MIN_CONFIRMATIONS  // Wait for 12 confirmations
);

await blockProcessor.ExecuteAsync(CancellationToken.None);

// Only processes blocks with at least 12 confirmations
// If latest block is 1000, will process up to block 988

From test: BlockProcessing/BlockProcessingTests.cs:231-267

Example 4: Filtering with Criteria

Process only specific transactions:

var blockProcessor = web3.Processing.Blocks.CreateBlockProcessor(steps =>
{
    // Only process transactions with non-zero value
    steps.TransactionStep.SetMatchCriteria(tx =>
        tx.Transaction.Value?.Value > 0);

    // Only process receipts for transaction index 0
    steps.TransactionReceiptStep.SetMatchCriteria(tx =>
        tx.Transaction.TransactionIndex.Value == 0);

    steps.TransactionReceiptStep.AddSynchronousProcessorHandler(tx =>
    {
        Console.WriteLine($"High-value transaction at index 0: {tx.TransactionHash}");
    });
});

await blockProcessor.ExecuteAsync(new BigInteger(110), CancellationToken.None, new BigInteger(100));

// Only transactions matching ALL criteria will be processed

From test: BlockProcessing/BlockProcessingTests.cs:134-161

Example 5: Disabling Processing Steps

Optimize by skipping unnecessary steps:

var blockProcessor = web3.Processing.Blocks.CreateBlockProcessor(steps =>
{
    // Only interested in blocks, not transactions
    steps.BlockStep.AddSynchronousProcessorHandler(block =>
    {
        Console.WriteLine($"Block {block.Number}: {block.TransactionCount} transactions");
    });
});

// Disable receipt and log processing for performance
blockProcessor.Orchestrator.TransactionWithReceiptCrawlerStep.Enabled = false;
blockProcessor.Orchestrator.FilterLogCrawlerStep.Enabled = false;

await blockProcessor.ExecuteAsync(new BigInteger(110), CancellationToken.None, new BigInteger(100));

// Receipts and logs won't be fetched or processed

From test: BlockProcessing/BlockProcessingTests.cs:76-106

Example 6: Block Storage Processor

Automatically store blockchain data to repositories:

using Nethereum.BlockchainProcessing.BlockStorage.Repositories;

var web3 = new Web3("https://mainnet.infura.io/v3/YOUR_KEY");

// In-memory storage (replace with your database implementation)
var context = new InMemoryBlockchainStorageRepositoryContext();
var repositoryFactory = new InMemoryBlockchainStorageRepositoryFactory(context);

var processor = web3.Processing.Blocks.CreateBlockStorageProcessor(
    repositoryFactory,
    minimumBlockConfirmations: 6
);

// Process and automatically store blocks, transactions, and logs
await processor.ExecuteAsync(
    toBlockNumber: new BigInteger(110),
    cancellationToken: CancellationToken.None,
    startAtBlockNumberIfNotProcessed: new BigInteger(100)
);

// Data is automatically persisted
Console.WriteLine($"Blocks stored: {context.Blocks.Count}");
Console.WriteLine($"Transactions stored: {context.Transactions.Count}");
Console.WriteLine($"Logs stored: {context.TransactionLogs.Count}");

From test: BlockStorage/BlockStorageProcessorTests.cs:16-39

Example 7: Custom Storage Configuration

Add custom processing alongside storage:

var repositoryFactory = new InMemoryBlockchainStorageRepositoryFactory(context);

var processor = web3.Processing.Blocks.CreateBlockStorageProcessor(
    repositoryFactory,
    minimumBlockConfirmations: 6,
    configureSteps: steps =>
    {
        // Add custom handler alongside automatic storage
        steps.BlockStep.AddSynchronousProcessorHandler(block =>
        {
            // Send notification, update cache, etc.
            Console.WriteLine($"New block stored: {block.Number}");
        });

        // Add custom filtering
        steps.TransactionStep.SetMatchCriteria(tx =>
            tx.Transaction.Value?.Value > Web3.Convert.ToWei(1));
    }
);

await processor.ExecuteAsync(new BigInteger(110), CancellationToken.None, new BigInteger(100));

Log Processing

For event-focused processing, use LogOrchestrator for efficient batch retrieval. Located in LogProcessing/LogOrchestrator.cs:13-214.

Example 8: Process All Logs

var web3 = new Web3("https://mainnet.infura.io/v3/YOUR_KEY");

var logsProcessed = new List<FilterLog>();

var logProcessor = web3.Processing.Logs.CreateProcessor(
    filterLog => logsProcessed.Add(filterLog)
);

// Batch retrieval of logs (more efficient than block-by-block)
await logProcessor.ExecuteAsync(
    toBlockNumber: new BigInteger(110),
    cancellationToken: CancellationToken.None,
    startAtBlockNumberIfNotProcessed: new BigInteger(100)
);

Console.WriteLine($"Processed {logsProcessed.Count} logs");

From test: LogProcessing/LogProcessingTests.cs:15-60

Example 9: Process Specific Event Type

Process typed events with automatic decoding:

using Nethereum.Contracts.Standards.ERC20.ContractDefinition;

var web3 = new Web3("https://mainnet.infura.io/v3/YOUR_KEY");

var transferEvents = new List<EventLog<TransferEventDTO>>();

var logProcessor = web3.Processing.Logs.CreateProcessor<TransferEventDTO>(
    transferEvent =>
    {
        Console.WriteLine($"Transfer: {transferEvent.Event.Value} from {transferEvent.Event.From} to {transferEvent.Event.To}");
        transferEvents.Add(transferEvent);
    }
);

await logProcessor.ExecuteAsync(
    toBlockNumber: new BigInteger(110),
    startAtBlockNumberIfNotProcessed: new BigInteger(100)
);

Console.WriteLine($"Total transfers: {transferEvents.Count}");

From test: LogProcessing/LogProcessingForEventTests.cs:15-41

Example 10: Event Processing with Criteria

Filter events during processing:

var largeTransfers = new List<EventLog<TransferEventDTO>>();

var logProcessor = web3.Processing.Logs.CreateProcessor<TransferEventDTO>(
    // Action
    action: transferEventLog =>
    {
        largeTransfers.Add(transferEventLog);
        return Task.CompletedTask;
    },
    // Criteria - only transfers over 1 ETH equivalent
    criteria: transferEventLog =>
    {
        var match = transferEventLog.Event.Value > Web3.Convert.ToWei(1);
        return Task.FromResult(match);
    }
);

await logProcessor.ExecuteAsync(
    toBlockNumber: new BigInteger(110),
    startAtBlockNumberIfNotProcessed: new BigInteger(100)
);

Console.WriteLine($"Large transfers: {largeTransfers.Count}");

From test: LogProcessing/LogProcessingForEventTests.cs:68-99

Example 11: Process Contract-Specific Events

Process events from specific contract:

var usdcAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";

var logProcessor = web3.Processing.Logs.CreateProcessorForContract<TransferEventDTO>(
    usdcAddress,
    transferEvent =>
    {
        Console.WriteLine($"USDC Transfer: {transferEvent.Event.Value}");
    }
);

await logProcessor.ExecuteAsync(new BigInteger(110), startAtBlockNumberIfNotProcessed: new BigInteger(100));

From: Services/BlockchainLogProcessingService.cs:185-218

Example 12: Process Multiple Contracts

var tokenAddresses = new[]
{
    "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
    "0xdAC17F958D2ee523a2206206994597C13D831ec7"  // USDT
};

var logProcessor = web3.Processing.Logs.CreateProcessorForContracts<TransferEventDTO>(
    tokenAddresses,
    transferEvent =>
    {
        Console.WriteLine($"Stablecoin Transfer at {transferEvent.Log.Address}: {transferEvent.Event.Value}");
    }
);

await logProcessor.ExecuteAsync(new BigInteger(110), startAtBlockNumberIfNotProcessed: new BigInteger(100));

From: Services/BlockchainLogProcessingService.cs:220-261

ERC20/ERC721 Processing

Example 13: ERC20 Transfer Processing

Built-in support for ERC20 token tracking:

using Nethereum.BlockchainProcessing.Services.SmartContracts;

var web3 = new Web3("https://mainnet.infura.io/v3/YOUR_KEY");
var erc20Service = new ERC20LogProcessingService(web3.Eth);

var usdcAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";

// Get all USDC transfers in block range
var transfers = await erc20Service.GetAllTransferEventsForContract(
    contractAddress: usdcAddress,
    fromBlockNumber: new BigInteger(100),
    toBlockNumber: new BigInteger(110),
    cancellationToken: CancellationToken.None
);

foreach (var transfer in transfers)
{
    Console.WriteLine($"Transfer: {transfer.Event.Value} from {transfer.Event.From} to {transfer.Event.To}");
    Console.WriteLine($"  Block: {transfer.Log.BlockNumber}, Tx: {transfer.Log.TransactionHash}");
}

From: Services/SmartContracts/ERC20LogProcessingService.cs:23-29

Example 14: Track Account Token Activity

Get all transfers involving specific account:

var tokenAddresses = new[]
{
    "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
    "0xdAC17F958D2ee523a2206206994597C13D831ec7"  // USDT
};

var accountAddress = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb";

// Get transfers TO and FROM the account
var accountTransfers = await erc20Service.GetAllTransferEventsFromAndToAccount(
    contractAddresses: tokenAddresses,
    account: accountAddress,
    fromBlockNumber: new BigInteger(100),
    toBlockNumber: new BigInteger(110)
);

var received = accountTransfers.Count(t => t.Event.To.Equals(accountAddress, StringComparison.OrdinalIgnoreCase));
var sent = accountTransfers.Count(t => t.Event.From.Equals(accountAddress, StringComparison.OrdinalIgnoreCase));

Console.WriteLine($"Received: {received}, Sent: {sent}");

From: Services/SmartContracts/ERC20LogProcessingService.cs:47-62

Example 15: ERC721 Ownership Tracking

Track NFT ownership from transfer events:

using Nethereum.BlockchainProcessing.Services.SmartContracts;

var web3 = new Web3("https://mainnet.infura.io/v3/YOUR_KEY");
var erc721Service = new ERC721LogProcessingService(web3.Eth);

var nftContract = "0xYourNFTContract";

// Get current owners by processing all transfer events
var owners = await erc721Service.GetAllCurrentOwnersProcessingAllTransferEvents(
    contractAddress: nftContract,
    fromBlockNumber: new BigInteger(0),  // Process all history
    toBlockNumber: null  // Up to latest
);

foreach (var owner in owners)
{
    Console.WriteLine($"Token #{owner.TokenId}: Owned by {owner.Owner}");
}

From: Services/SmartContracts/ERC721LogProcessingService.cs:51-58

Example 16: Account NFT Portfolio

Get all NFTs owned by an account:

var accountAddress = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb";
var nftContract = "0xYourNFTContract";

var ownedNFTs = await erc721Service.GetErc721OwnedByAccountUsingAllTransfers(
    contractAddress: nftContract,
    account: accountAddress,
    fromBlockNumber: new BigInteger(0),
    toBlockNumber: null
);

Console.WriteLine($"Account owns {ownedNFTs.Count} NFTs:");
foreach (var nft in ownedNFTs)
{
    Console.WriteLine($"  Token #{nft.TokenId}");
}

From: Services/SmartContracts/ERC721LogProcessingService.cs:26-36

Progress Tracking

JSON File Progress Repository

Persist progress to JSON file:

using Nethereum.BlockchainProcessing.ProgressRepositories;
using System.IO;

var progressFile = "blockchain-progress.json";

var progressRepository = new JsonBlockProgressRepository(
    jsonSourceExists: async () => File.Exists(progressFile),
    jsonWriter: async (json) => await File.WriteAllTextAsync(progressFile, json),
    jsonRetriever: async () => await File.ReadAllTextAsync(progressFile),
    lastBlockProcessed: new BigInteger(0)  // Starting block if file doesn't exist
);

var blockProcessor = web3.Processing.Blocks.CreateBlockProcessor(
    progressRepository,
    steps => { /* configure steps */ }
);

// Progress automatically persists to JSON file
await blockProcessor.ExecuteAsync(CancellationToken.None);

// Resume from same file on next run

From: ProgressRepositories/JsonBlockProgressRepository.cs:13-82

Custom Progress Repository

Implement IBlockProgressRepository for custom storage:

public class DatabaseProgressRepository : IBlockProgressRepository
{
    private readonly IDbConnection _connection;

    public DatabaseProgressRepository(IDbConnection connection)
    {
        _connection = connection;
    }

    public async Task UpsertProgressAsync(BigInteger blockNumber)
    {
        await _connection.ExecuteAsync(
            "UPDATE BlockchainProgress SET LastBlock = @blockNumber, UpdatedAt = @now",
            new { blockNumber = (long)blockNumber, now = DateTime.UtcNow }
        );
    }

    public async Task<BigInteger?> GetLastBlockNumberProcessedAsync()
    {
        var result = await _connection.QuerySingleOrDefaultAsync<long?>(
            "SELECT LastBlock FROM BlockchainProgress"
        );
        return result.HasValue ? new BigInteger(result.Value) : null;
    }
}

From interface: ProgressRepositories/IBlockProgressRepository.cs:5-10

Storage System

Implementing Custom Storage

Implement IBlockchainStoreRepositoryFactory for your database:

public class MyDatabaseRepositoryFactory : IBlockchainStoreRepositoryFactory
{
    private readonly IDbConnection _connection;

    public MyDatabaseRepositoryFactory(IDbConnection connection)
    {
        _connection = connection;
    }

    public IBlockRepository CreateBlockRepository()
    {
        return new MyBlockRepository(_connection);
    }

    public ITransactionRepository CreateTransactionRepository()
    {
        return new MyTransactionRepository(_connection);
    }

    public ITransactionLogRepository CreateTransactionLogRepository()
    {
        return new MyTransactionLogRepository(_connection);
    }

    public IContractRepository CreateContractRepository()
    {
        return new MyContractRepository(_connection);
    }

    public IAddressTransactionRepository CreateAddressTransactionRepository()
    {
        return new MyAddressTransactionRepository(_connection);
    }

    public ITransactionVMStackRepository CreateTransactionVMStackRepository()
    {
        return new MyTransactionVMStackRepository(_connection);
    }
}

From: BlockStorage/Repositories/IBlockchainStoreRepositoryFactory.cs:5-11

Storage Entities

The package provides ready-to-use entity models:

Block Entity (BlockStorage/Entities/Block.cs):

  • BlockNumber, Hash, ParentHash, Nonce, Difficulty
  • Miner, GasUsed, GasLimit, Timestamp
  • TransactionCount, BaseFeePerGas

Transaction Entity (BlockStorage/Entities/Transaction.cs):

  • Hash, BlockNumber, TransactionIndex
  • AddressFrom, AddressTo, Value, Gas, GasPrice, GasUsed
  • NewContractAddress, Failed, ReceiptHash
  • MaxFeePerGas, MaxPriorityFeePerGas (EIP-1559)

TransactionLog Entity (BlockStorage/Entities/TransactionLog.cs):

  • TransactionHash, LogIndex, Address
  • EventHash (Topics[0])
  • IndexVal1, IndexVal2, IndexVal3 (Indexed parameters)
  • Data (Non-indexed parameters)

Contract Entity (BlockStorage/Entities/Contract.cs):

  • Address, Name, ABI, Code
  • Creator, TransactionHash

Advanced Configuration

Log Processing Batch Size

Configure batch size for log retrieval:

using Nethereum.BlockchainProcessing.LogProcessing;

var logProcessor = web3.Processing.Logs.CreateProcessor(filterLog => { /* ... */ });

// Customize batch size (default: 1,000,000 blocks)
logProcessor.Orchestrator.BlockRangeRequestStrategy = new BlockRangeRequestStrategy(
    defaultNumberOfBlocksPerRequest: 10000,  // 10k blocks per batch
    retryWeight: 50  // Reduce batch size on failures
);

await logProcessor.ExecuteAsync(new BigInteger(110), startAtBlockNumberIfNotProcessed: new BigInteger(100));

From: Services/BlockchainLogProcessingService.cs:24-25

Retry Configuration

Configure retry behavior for log retrieval:

var logProcessor = web3.Processing.Logs.CreateProcessor(filterLog => { /* ... */ });

// Configure retries (default: 10 retries)
logProcessor.Orchestrator.MaxGetLogsRetries = 5;
logProcessor.Orchestrator.MaxGetLogsNullRetries = 2;

await logProcessor.ExecuteAsync(new BigInteger(110), startAtBlockNumberIfNotProcessed: new BigInteger(100));

From: LogProcessing/LogOrchestrator.cs:57-58

Parallel vs Sequential Log Processing

Choose processing strategy:

using Nethereum.BlockchainProcessing.LogProcessing;

var logProcessor = web3.Processing.Logs.CreateProcessor(filterLog => { /* ... */ });

// Sequential processing (default for most use cases)
logProcessor.Orchestrator.LogProcessStrategy = new LogProcessSequentialStrategy();

// Parallel processing (faster but uses more resources)
logProcessor.Orchestrator.LogProcessStrategy = new LogProcessParallelStrategy();

await logProcessor.ExecuteAsync(new BigInteger(110), startAtBlockNumberIfNotProcessed: new BigInteger(100));

From: LogProcessing/LogOrchestrator.cs:64, LogProcessing/ILogProcessStrategy.cs

Contract Creation Code Retrieval

Enable code retrieval for deployed contracts:

var blockProcessor = web3.Processing.Blocks.CreateBlockProcessor(steps =>
{
    steps.ContractCreationStep.AddSynchronousProcessorHandler(contractCreation =>
    {
        Console.WriteLine($"Contract deployed at: {contractCreation.ContractAddress}");
        Console.WriteLine($"Code length: {contractCreation.Code?.Length ?? 0}");
    });
});

// Enable code retrieval (requires extra RPC call per contract)
blockProcessor.Orchestrator.ContractCreatedCrawlerStep.RetrieveCode = true;

await blockProcessor.ExecuteAsync(new BigInteger(110), CancellationToken.None, new BigInteger(100));

From: BlockProcessing/CrawlerSteps/ContractCreatedCrawlerStep.cs:9, 21

Performance Considerations

Block Processing Performance

Block-by-block processing:

  • Fetches full block data with transactions
  • For each transaction, fetches receipt (separate RPC call)
  • RPC calls: 1 (block) + N (receipts) per block
  • Best for: Complete blockchain indexing

Optimization tips:

  1. Disable unused steps
  2. Use criteria to filter early
  3. Increase minimum confirmations to avoid reorgs
  4. Process in batches with multiple processors

Log Processing Performance

Batch log retrieval:

  • Fetches all logs in block range (single RPC call)
  • RPC calls: Blocks / BatchSize
  • Best for: Event-focused applications

Batch size considerations:

  • Default: 1,000,000 blocks per batch
  • Reduce for nodes with rate limits
  • Increase for archive nodes
  • Auto-reduces on errors via BlockRangeRequestStrategy

From: LogProcessing/LogOrchestrator.cs:153-194

RPC Call Comparison

Process 1000 blocks with 20 transactions each:

Block Processing:

  • 1000 block fetches
  • 20,000 receipt fetches
  • Total: 21,000 RPC calls

Log Processing (batch):

  • 1 log fetch (if 1000 blocks < batch size)
  • Total: 1 RPC call

Recommendation: Use LogOrchestrator for event tracking, BlockCrawlOrchestrator for complete data.

Error Handling

Orchestrator Error Handling

Orchestrators return error status:

var progress = await blockProcessor.Orchestrator.ProcessAsync(
    fromNumber: new BigInteger(100),
    toNumber: new BigInteger(110),
    cancellationToken: CancellationToken.None
);

if (progress.HasErrored)
{
    Console.WriteLine($"Error processing block {progress.BlockNumberProcessTo}:");
    Console.WriteLine(progress.Exception.Message);

    // Can resume from failed block
    await blockProcessor.ExecuteAsync(
        toBlockNumber: new BigInteger(110),
        cancellationToken: CancellationToken.None,
        startAtBlockNumberIfNotProcessed: progress.BlockNumberProcessTo
    );
}

From: Orchestrator/OrchestrationProgress.cs:6-11

Handler Error Handling

Wrap handlers in try-catch for graceful error handling:

var blockProcessor = web3.Processing.Blocks.CreateBlockProcessor(steps =>
{
    steps.TransactionStep.AddProcessorHandler(async tx =>
    {
        try
        {
            await ProcessTransactionAsync(tx);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error processing transaction {tx.Transaction.TransactionHash}: {ex.Message}");
            // Log error, send alert, etc.
        }
    });
});

Log Processing Retry

Log processing has built-in retry with exponential backoff:

// Automatically retries on RPC errors
// Reduces batch size on repeated failures
// Configured via MaxGetLogsRetries and BlockRangeRequestStrategy

From: LogProcessing/LogOrchestrator.cs:153-194

Use Cases

Blockchain Explorer

Build complete blockchain indexer:

var repositoryFactory = CreateDatabaseRepositoryFactory();

var processor = web3.Processing.Blocks.CreateBlockStorageProcessor(
    repositoryFactory,
    minimumBlockConfirmations: 12,
    configureSteps: steps =>
    {
        // Index all data
        // Storage handlers are automatically added

        // Add custom indexing
        steps.TransactionStep.AddProcessorHandler(async tx =>
        {
            await UpdateAddressBalanceCache(tx);
        });
    }
);

// Process continuously
await processor.ExecuteAsync(cancellationToken);

DEX Event Tracker

Track Uniswap swaps:

var swapEvents = new List<EventLog<SwapEventDTO>>();

var logProcessor = web3.Processing.Logs.CreateProcessor<SwapEventDTO>(
    swapEvent =>
    {
        var pool = swapEvent.Log.Address;
        var swap = swapEvent.Event;

        Console.WriteLine($"Swap on {pool}:");
        Console.WriteLine($"  Amount0In: {swap.Amount0In}");
        Console.WriteLine($"  Amount1Out: {swap.Amount1Out}");

        swapEvents.Add(swapEvent);
    }
);

await logProcessor.ExecuteAsync(toBlockNumber, startAtBlockNumberIfNotProcessed: fromBlockNumber);

Token Balance Tracker

Track token balances for addresses:

var balances = new Dictionary<string, BigInteger>();

var erc20Service = new ERC20LogProcessingService(web3.Eth);

var transfers = await erc20Service.GetAllTransferEventsForContract(
    usdcAddress,
    fromBlockNumber,
    toBlockNumber,
    CancellationToken.None
);

foreach (var transfer in transfers)
{
    var from = transfer.Event.From;
    var to = transfer.Event.To;
    var value = transfer.Event.Value;

    balances[from] = (balances.GetValueOrDefault(from)) - value;
    balances[to] = (balances.GetValueOrDefault(to)) + value;
}

foreach (var (address, balance) in balances)
{
    Console.WriteLine($"{address}: {balance}");
}

NFT Transfer Monitor

Monitor NFT transfers in real-time:

var progressRepo = new JsonBlockProgressRepository(/* ... */);

var logProcessor = web3.Processing.Logs.CreateProcessor<TransferEventDTO>(
    progressRepo,
    transferEvent =>
    {
        Console.WriteLine($"NFT Transfer:");
        Console.WriteLine($"  Token: {transferEvent.Event.TokenId}");
        Console.WriteLine($"  From: {transferEvent.Event.From}");
        Console.WriteLine($"  To: {transferEvent.Event.To}");
        Console.WriteLine($"  Tx: {transferEvent.Log.TransactionHash}");

        // Send notification, update database, etc.
    }
);

// Run continuously
await logProcessor.ExecuteAsync(CancellationToken.None);

Dependencies

Required packages:

  • Nethereum.Hex - Hex conversions
  • Nethereum.JsonRpc.RpcClient - RPC client
  • Nethereum.RPC - RPC DTOs and services
  • Nethereum.Util - Utility functions
  • Nethereum.Contracts - Contract interaction and event decoding

Source Files Reference

Core Processing:

  • BlockchainProcessor.cs - Main processor
  • BlockchainCrawlingProcessor.cs - Block crawling processor
  • Orchestrator/IBlockchainProcessingOrchestrator.cs - Orchestrator interface

Block Processing:

  • BlockProcessing/BlockProcessingSteps.cs - Pipeline steps
  • BlockProcessing/BlockCrawlOrchestrator.cs - Block crawling orchestrator
  • BlockProcessing/CrawlerSteps/*.cs - Data fetchers

Log Processing:

  • LogProcessing/LogOrchestrator.cs - Log batch processor
  • LogProcessing/BlockRangeRequestStrategy.cs - Batch sizing strategy

Processor Framework:

  • Processor/IProcessor.cs - Processor interface
  • Processor/Processor.cs - Generic processor
  • Processor/ProcessorHandler.cs - Handler wrapper

Storage:

  • BlockStorage/Repositories/IBlockchainStoreRepositoryFactory.cs - Repository factory
  • BlockStorage/Entities/*.cs - Storage entities
  • BlockStorage/BlockStorageProcessingSteps.cs - Storage handlers

Progress:

  • ProgressRepositories/IBlockProgressRepository.cs - Progress interface
  • ProgressRepositories/JsonBlockProgressRepository.cs - JSON persistence

Services:

  • Services/BlockchainProcessingService.cs - Service entry point
  • Services/BlockchainLogProcessingService.cs - Log processing service
  • Services/SmartContracts/ERC20LogProcessingService.cs - ERC20 utilities
  • Services/SmartContracts/ERC721LogProcessingService.cs - ERC721 utilities

License

Nethereum is licensed under the MIT License.

  • Nethereum.Web3 - Ethereum client library
  • Nethereum.Contracts - Smart contract interaction
  • Nethereum.RPC - RPC infrastructure

Support

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net451 is compatible.  net452 was computed.  net46 was computed.  net461 is compatible.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (8)

Showing the top 5 NuGet packages that depend on Nethereum.BlockchainProcessing:

Package Downloads
Nethereum.Web3

Nethereum.Web3 Ethereum Web3 Class Library to interact via RPC with an Ethereum client, for example geth. Including contract interaction, deployment, transaction, encoding / decoding and event filters

Nethereum.Web3Lite

Nethereum.Web3Lite Ethereum Web3 Class Library (light browser version, with no reference to signing crypto libraries) to interact via RPC with an Ethereum client, for example geth. Including contract interaction, deployment, transaction, encoding / decoding and event filters

Wonka.Eth

Relying heavily on the Nethereum project, this library contains classes that interact with the Ethereum foundation and that extend the Wonka engine, particulary the base class WonkaBizRulesEngine in the Wonka.BizRulesEngine library. With the funtionality provided here, Wonka becomes a business rules engine for both the .NET platform and the Ethereum platform, one that is inherently metadata-driven and serves as a reference implementation for EIP-2746. Once the rules are written into a markup language and are parsed/deserialized by the .NET form of the engine, these rules can then be serialized onto the blockchain using Nethereum, and stored within a smart contract (i.e., the Ethereum version of the engine) built using the Solidity language. The Ethereum version of this engine can also be deployed as a contract by this library. After providing a number of rules and populating a record, a user can submit the populated record for validation by the rules engine, whether it exists in .NET or the blockchain.

Tricksfor.DistributedNonce

Distributed Nonce provides an easy-to-use block chain Nonce handler in scalable environment.

Nethereum.BlockchainStore.Search

Add Ethereum block chain data to Azure or Elastic Search. Easily index events and transactions with minimal config. Data can be auto mapped to search documents or create your own search DTO's and mapping. Supports filtering to ensure you only index what you want.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.8.0 1,071 1/6/2026
5.0.0 296,103 5/28/2025
4.29.0 211,481 2/10/2025
4.28.0 61,952 1/7/2025
4.27.1 12,522 12/24/2024
4.27.0 1,632 12/24/2024
4.26.0 95,835 10/1/2024
4.25.0 22,993 9/19/2024
4.21.4 96,551 8/9/2024
4.21.3 10,400 8/5/2024
4.21.2 68,118 6/26/2024
4.21.1 2,570 6/26/2024
4.21.0 10,356 6/18/2024
4.20.0 315,062 3/28/2024
4.19.0 65,732 2/16/2024
4.18.0 270,140 11/21/2023
4.17.1 77,631 9/28/2023
4.17.0 16,827 9/27/2023
4.16.0 117,622 8/14/2023
4.15.2 128,229 7/11/2023
4.15.1 3,820 7/11/2023
4.15.0 4,362 7/11/2023
4.14.0 188,553 3/19/2023
4.13.0 131,048 2/18/2023
4.12.0 268,083 12/9/2022
4.11.0 173,091 10/27/2022
4.9.0 111,163 9/27/2022
4.8.0 178,344 8/24/2022
4.7.0 147,913 7/20/2022
4.6.1 128,794 6/18/2022
4.6.0 8,741 6/16/2022
4.5.0 388,738 5/13/2022
4.4.1 104,923 4/27/2022
4.4.0 12,272 4/27/2022
4.3.0 63,203 4/12/2022
4.2.0 171,121 2/18/2022
4.1.1 485,637 11/4/2021
4.1.0 28,833 10/15/2021
4.0.5 138,234 8/12/2021
4.0.4 7,096 8/10/2021
4.0.3 7,074 8/8/2021
4.0.2 6,246 8/5/2021
4.0.1 11,791 7/28/2021
4.0.0 17,231 7/26/2021
3.8.0 384,198 7/3/2020
3.7.1 115,076 2/13/2020
3.7.0 8,844 2/13/2020
3.6.0 32,035 1/27/2020
3.5.0 19,427 12/31/2019
3.4.0 146,632 7/29/2019
3.1.2 4,447 3/13/2019