![]() |
VOOZH | about |
dotnet add package Nethereum.BlockchainProcessing --version 6.1.0
NuGet\Install-Package Nethereum.BlockchainProcessing -Version 6.1.0
<PackageReference Include="Nethereum.BlockchainProcessing" Version="6.1.0" />
<PackageVersion Include="Nethereum.BlockchainProcessing" Version="6.1.0" />Directory.Packages.props
<PackageReference Include="Nethereum.BlockchainProcessing" />Project file
paket add Nethereum.BlockchainProcessing --version 6.1.0
#r "nuget: Nethereum.BlockchainProcessing, 6.1.0"
#:package Nethereum.BlockchainProcessing@6.1.0
#addin nuget:?package=Nethereum.BlockchainProcessing&version=6.1.0Install as a Cake Addin
#tool nuget:?package=Nethereum.BlockchainProcessing&version=6.1.0Install as a Cake Tool
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.
This package enables applications to:
ILogProcessingObserverdotnet add package Nethereum.BlockchainProcessing
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)
│ └── InternalTransactionOrchestrator (trace-based indexing)
├── BlockProcessingSteps (pipeline stages)
├── IBlockProgressRepository (progress tracking)
│ └── ReorgBufferedBlockProgressRepository (decorator)
├── IChainStateRepository (reorg detection state)
├── ILastConfirmedBlockNumberService (confirmation management)
└── ILogProcessingObserver (metrics/telemetry)
Main processor that manages continuous blockchain processing. Located in BlockchainProcessor.cs.
Key Methods:
ExecuteAsync(CancellationToken, BigInteger?) - Process until cancelledExecuteAsync(BigInteger toBlockNumber, ...) - Process to specific blockFeatures:
IBlockProgressRepositoryOrchestrates crawling of blocks, transactions, receipts, and logs. Located in BlockProcessing/BlockCrawlOrchestrator.cs.
Processing Flow:
BlockCrawlerStepTransactionCrawlerStepTransactionReceiptCrawlerStepContractCreatedCrawlerStep (if applicable)FilterLogCrawlerStepDefines processing pipeline stages. Located in BlockProcessing/BlockProcessingSteps.cs.
Steps:
BlockStep - Processes BlockWithTransactionsTransactionStep - Processes TransactionVOTransactionReceiptStep - Processes TransactionReceiptVOFilterLogStep - Processes FilterLogVOContractCreationStep - Processes ContractCreationVOEach step is a Processor<T> that can have multiple handlers.
Generic processor that executes multiple handlers. Located in Processor/Processor.cs.
Key Features:
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
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
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
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
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
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
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));
For event-focused processing, use LogOrchestrator for efficient batch retrieval. Located in LogProcessing/LogOrchestrator.cs.
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
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
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
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
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
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
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
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
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
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
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
The processor supports chain reorganisation detection and recovery via ChainConsistencyValidationService and IChainStateRepository.
ChainState tracks the last known canonical block number and hash. After each block is processed, the state is updated. On startup, the stored hash is compared against the RPC node — if they differ, a reorg is detected.
using Nethereum.BlockchainProcessing.BlockStorage.Entities;
using Nethereum.BlockchainProcessing.ProgressRepositories;
using Nethereum.BlockchainProcessing.Services;
var chainStateRepo = new MyChainStateRepository(); // implements IChainStateRepository
var validator = new ChainConsistencyValidationService(web3.Eth, chainStateRepo);
validator.ReorgBuffer = 10; // rewind 10 blocks on reorg detection
try
{
await validator.ValidateAsync(cancellationToken);
}
catch (ReorgDetectedException ex)
{
Console.WriteLine($"Reorg detected at block {ex.LastCanonicalBlockNumber}");
Console.WriteLine($"Rewinding to block {ex.RewindToBlockNumber}");
// Mark non-canonical records, rewind progress, restart processing
}
From: Services/ChainConsistencyValidationService.cs
Prevents accidental indexing of the wrong chain by comparing the RPC chain ID against the stored value:
await ChainStateValidationService.EnsureChainIdMatchesAsync(
web3.Eth, chainStateRepositoryFactory);
// Throws InvalidOperationException if chain IDs don't match
From: Services/ChainStateValidationService.cs
Wraps any IBlockProgressRepository to subtract a reorg buffer from the reported last block, ensuring blocks within the buffer are always re-processed:
var innerProgress = new InMemoryBlockchainProgressRepository();
var bufferedProgress = new ReorgBufferedBlockProgressRepository(innerProgress, reorgBuffer: 12);
// If inner reports block 100 as last processed, buffered returns 88
var lastBlock = await bufferedProgress.GetLastBlockNumberProcessedAsync();
From: ProgressRepositories/ReorgBufferedBlockProgressRepository.cs
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
The package provides ready-to-use entity models:
Block Entity (BlockStorage/Entities/Block.cs):
Transaction Entity (BlockStorage/Entities/TransactionBase.cs):
TransactionLog Entity (BlockStorage/Entities/TransactionLog.cs):
Contract Entity (BlockStorage/Entities/Contract.cs):
InternalTransaction Entity (BlockStorage/Entities/InternalTransaction.cs):
TokenTransferLog Entity (BlockStorage/Entities/TokenTransferLog.cs):
TokenBalance Entity (BlockStorage/Entities/TokenBalance.cs):
TokenMetadata Entity (BlockStorage/Entities/TokenMetadata.cs):
NFTInventory Entity (BlockStorage/Entities/NFTInventory.cs):
AccountState Entity (BlockStorage/Entities/AccountState.cs):
ChainState Entity (BlockStorage/Entities/ChainState.cs):
All numeric indexing fields (BlockNumber, LogIndex, TransactionIndex, Nonce, Timestamp, TransactionType, TransactionCount) use long. Gas and value fields (Value, Gas, GasPrice, GasUsed, Balance, Amount) remain string to preserve full uint256 precision.
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
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
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
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
Block-by-block processing:
Optimization tips:
Batch log retrieval:
Batch size considerations:
BlockRangeRequestStrategyFrom: LogProcessing/LogOrchestrator.cs:153-194
Process 1000 blocks with 20 transactions each:
Block Processing:
Log Processing (batch):
Recommendation: Use LogOrchestrator for event tracking, BlockCrawlOrchestrator for complete data.
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
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 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
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);
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);
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}");
}
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);
The TokenTransferLogProcessingService indexes ERC-20, ERC-721, and ERC-1155 transfer events into ITokenTransferLogRepository with a unified filter that matches all three token standards in a single log query.
using Nethereum.BlockchainProcessing.Services.SmartContracts;
var tokenService = new TokenTransferLogProcessingService(
web3.Processing.Logs, web3.Eth);
var processor = tokenService.CreateProcessor(
transferLogRepository, blockProgressRepository,
numberOfBlocksPerRequest: 1000);
await processor.ExecuteAsync(cancellationToken);
From: Services/SmartContracts/TokenTransferLogProcessingService.cs
The TokenBalanceAggregationService reads stored TokenTransferLog records and maintains running TokenBalance and NFTInventory tables:
var aggregationService = new TokenBalanceAggregationService(
transferLogRepository, balanceRepository, nftRepository, progressRepository);
await aggregationService.AggregateAsync(fromBlock, toBlock, cancellationToken);
From: Services/SmartContracts/TokenBalanceAggregationService.cs
The InternalTransactionPostProcessor orchestrates trace-based internal transaction indexing. It accepts a trace provider function (e.g., debug_traceTransaction) and stores results via IInternalTransactionRepository:
var postProcessor = new InternalTransactionPostProcessor(
internalTransactionRepository,
traceProvider: async txHash => await GetTracesFromRpc(txHash),
getContractTransactionsInRange: async (from, to) => await GetContractTxs(from, to),
progressRepository, lastConfirmedBlockService);
await postProcessor.ExecuteAsync(cancellationToken);
From: Services/InternalTransactionPostProcessor.cs
The ILogProcessingObserver interface enables telemetry integration. The built-in LogProcessingMetrics implementation uses System.Diagnostics.Metrics (net8.0+) for OpenTelemetry-compatible instrumentation:
using Nethereum.BlockchainProcessing.Metrics;
var metrics = new LogProcessingMetrics(
chainId: "1", processorType: "TokenTransfers", name: "MyApp");
// Pass to log processing service
var processor = logProcessingService.CreateProcessor(
transferLogRepository, blockProgressRepository,
observer: metrics);
// Emitted metrics:
// logprocessing.blocks.processed - counter
// logprocessing.logs.processed - counter
// logprocessing.errors - counter
// logprocessing.reorgs - counter
// logprocessing.getlogs.retries - counter
// logprocessing.batch.duration - histogram
// logprocessing.last_block - gauge
// logprocessing.lag - gauge (blocks behind chain head)
From: Metrics/LogProcessingMetrics.cs
RetryRunner.RunWithExponentialBackoffAsync provides resilient execution with exponential backoff for long-running processing loops:
using Nethereum.BlockchainProcessing;
await RetryRunner.RunWithExponentialBackoffAsync(
async ct =>
{
await processor.ExecuteAsync(ct);
},
cancellationToken,
onRetry: (ex, attempt, delay) =>
logger.LogError(ex, "Processing failed (attempt {Attempt}), retrying in {Delay}s", attempt, delay),
initialDelaySeconds: 5,
maxDelaySeconds: 300);
From: RetryRunner.cs
Repository interfaces for marking records as non-canonical during reorg recovery:
INonCanonicalBlockRepository — MarkNonCanonicalAsync(BigInteger blockNumber)INonCanonicalTransactionRepository — MarkNonCanonicalAsync(BigInteger blockNumber)INonCanonicalTransactionLogRepository — MarkNonCanonicalAsync(BigInteger blockNumber)INonCanonicalTokenTransferLogRepository — MarkNonCanonicalAsync(BigInteger blockNumber)IReorgHandler — composite interface combining all non-canonical operations with HandleReorgAsync(BigInteger fromBlock)From: BlockStorage/Repositories/INonCanonical*.cs, BlockStorage/Repositories/IReorgHandler.cs
Required packages:
Core Processing:
BlockchainProcessor.cs - Main processorBlockchainCrawlingProcessor.cs - Block crawling processorOrchestrator/IBlockchainProcessingOrchestrator.cs - Orchestrator interfaceBlock Processing:
BlockProcessing/BlockProcessingSteps.cs - Pipeline stepsBlockProcessing/BlockCrawlOrchestrator.cs - Block crawling orchestratorBlockProcessing/CrawlerSteps/*.cs - Data fetchersLog Processing:
LogProcessing/LogOrchestrator.cs - Log batch processorLogProcessing/BlockRangeRequestStrategy.cs - Batch sizing strategyProcessor Framework:
Processor/IProcessor.cs - Processor interfaceProcessor/Processor.cs - Generic processorProcessor/ProcessorHandler.cs - Handler wrapperStorage:
BlockStorage/Repositories/IBlockchainStoreRepositoryFactory.cs - Repository factoryBlockStorage/Entities/*.cs - Storage entitiesBlockStorage/BlockStorageProcessingSteps.cs - Storage handlersProgress:
ProgressRepositories/IBlockProgressRepository.cs - Progress interfaceProgressRepositories/JsonBlockProgressRepository.cs - JSON persistenceProgressRepositories/IChainStateRepository.cs - Chain state trackingProgressRepositories/ReorgBufferedBlockProgressRepository.cs - Reorg-buffered progressServices:
Services/BlockchainProcessingService.cs - Service entry pointServices/BlockchainLogProcessingService.cs - Log processing serviceServices/ChainConsistencyValidationService.cs - Reorg detectionServices/ChainStateValidationService.cs - Chain ID validationServices/InternalTransactionPostProcessor.cs - Trace-based internal transaction indexingServices/SmartContracts/ERC20LogProcessingService.cs - ERC20 utilitiesServices/SmartContracts/ERC721LogProcessingService.cs - ERC721 utilitiesServices/SmartContracts/TokenTransferLogProcessingService.cs - Unified token transfer indexingServices/SmartContracts/TokenBalanceAggregationService.cs - Balance aggregation from transfersMetrics:
Metrics/ILogProcessingObserver.cs - Observer interfaceMetrics/LogProcessingMetrics.cs - OpenTelemetry metrics implementationInfrastructure:
RetryRunner.cs - Exponential backoff retry runner| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 is compatible. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net451 net451 is compatible. net452 net452 was computed. net46 net46 was computed. net461 net461 is compatible. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
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 |
|
|
Nethereum.Mud.Repositories.EntityFramework
Nethereum.Mud.Repositories.EntityFramework Nethereum Web3 Class Library providing the EF context Table Repositories to sync with the Store contracts of the Mud framework https://mud.dev/ (Encoding, Repositories, Resources, Schema, TableRecords) |
|
|
Tricksfor.DistributedNonce
Distributed Nonce provides an easy-to-use block chain Nonce handler in scalable environment. |
|
|
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. |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 6.1.0 | 48,941 | 3/25/2026 |
| 6.0.4 | 10,203 | 3/18/2026 |
| 6.0.3 | 1,526 | 3/18/2026 |
| 6.0.1 | 2,449 | 3/17/2026 |
| 6.0.0 | 3,653 | 3/16/2026 |
| 5.8.0 | 78,935 | 1/6/2026 |
| 5.0.0 | 407,361 | 5/28/2025 |
| 4.29.0 | 295,933 | 2/10/2025 |
| 4.28.0 | 76,729 | 1/7/2025 |
| 4.27.1 | 13,849 | 12/24/2024 |
| 4.27.0 | 7,307 | 12/24/2024 |
| 4.26.0 | 102,649 | 10/1/2024 |
| 4.25.0 | 33,392 | 9/19/2024 |
| 4.21.4 | 127,881 | 8/9/2024 |
| 4.21.3 | 10,534 | 8/5/2024 |
| 4.21.2 | 75,284 | 6/26/2024 |
| 4.21.1 | 3,588 | 6/26/2024 |
| 4.21.0 | 17,223 | 6/18/2024 |
| 4.20.0 | 370,791 | 3/28/2024 |