This guide will walk you through the process of setting up and using Argus, from installation to running your first blockchain indexer application. You'll learn how to transform raw Cardano blockchain data into structured database records that can be easily queried and analyzed.
Prerequisites
Before getting started, ensure you have the following:
- .NET 8.0 SDK or later installed
- PostgreSQL database installed and running
- Access to a Cardano node (local or remote)
If you don't have a local Cardano node, you can use remote node services like those offered by Demeter.run. This guide works with both local and remote node options.
Overview of Argus
Argus is a blockchain indexing framework that transforms raw Cardano blockchain data into structured database records. Before diving into the implementation details, here's a high-level overview of how Argus works:
Key Components
- Data Models - Define what blockchain data you want to extract and store
- Database Context - Provides persistence and entity configuration
- Reducers - Convert blockchain data into your application-specific models
- Configuration - Connect to a Cardano node and set synchronization parameters
- Services - Register and configure the components for automatic operation
Argus simplifies blockchain data processing by connecting to a Cardano node, reading blockchain data, processing it through reducers, and storing results in your database. The framework handles synchronization tracking, chain rollbacks, and data integrity automatically. By following this guide, you'll create a complete indexing application customized to your specific data needs.
Step-by-Step Guide
1. Install Required Packages
First, create a new .NET project and add the necessary packages:
# Create a new web application
dotnet new web -n ArgusExample
# Navigate to the project directory
cd ArgusExample
# Install the main package
dotnet add package Argus.Sync --version 0.3.1-alpha
# Required dependencies
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
What are these packages for?
These packages supply all the necessary tools to connect with a Cardano node, handle blockchain data processing, and save the data in a PostgreSQL database:
- Argus.Sync: The core library that provides blockchain indexing functionality.
- Microsoft.EntityFrameworkCore.Design: Required for EF Core migrations and database schema generation.
- Npgsql.EntityFrameworkCore.PostgreSQL: PostgreSQL provider for Entity Framework Core.
2. Define Your Data Models
Create models that represent the blockchain data you want to store:
using Argus.Sync.Data.Models;
// Define your model
public record BlockInfo(
string Hash, // Block hash
ulong Number, // Block number
ulong Slot, // Block slot number
) : IReducerModel;
The IReducerModel
interface is a marker interface in Argus that your data models must inherit from to be used with the framework. While it doesn't define any methods or properties, this inheritance is required for your models to be properly integrated with the Argus reducers system.
3. Set Up Database Context
Create a database context to manage your models:
using Argus.Sync.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
public class MyDbContext(
DbContextOptions options,
IConfiguration configuration
) : CardanoDbContext(options, configuration)
{
public DbSet<BlockInfo> Blocks => Set<BlockInfo>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<BlockInfo>(entity =>
{
entity.HasKey(e => e.Hash);
entity.Property(e => e.CreatedAt).HasDefaultValueSql("now()");
});
}
}
The CardanoDbContext
is a specialized Entity Framework Core DbContext
that needs to be inherited by your database context. This inheritance provides the essential Argus framework integration, allowing your database to interact with the blockchain data processing pipeline.
We connect to our database schema by defining a DbSet, which corresponds to the BlockInfo
model we created earlier.
4. Implement Reducers
Create reducers that process blockchain data:
using Argus.Sync.Reducers;
using Chrysalis.Cbor.Types.Cardano.Core;
using Microsoft.EntityFrameworkCore;
public class BlockReducer(IDbContextFactory<MyDbContext> dbContextFactory)
: IReducer<BlockInfo>
{
public async Task RollForwardAsync(Block block)
{
// Extract block data
string hash = block.Header().Hash();
ulong number = block.Header().HeaderBody().BlockNumber();
ulong slot = block.Header().HeaderBody().Slot();
// Store in database
using var db = dbContextFactory.CreateDbContext();
db.Blocks.Add(new BlockInfo(hash, number, slot, DateTime.UtcNow));
await db.SaveChangesAsync();
}
public async Task RollBackwardAsync(ulong slot)
{
// Remove any blocks at or after the rollback slot
using var db = dbContextFactory.CreateDbContext();
db.Blocks.RemoveRange(
db.Blocks.Where(b => b.Slot >= slot)
);
await db.SaveChangesAsync();
}
}
The IReducer<T>
interface is at the core of Argus' data processing pipeline. It defines how blockchain data is transformed and stored in your database. The T
in IReducer<T>
is your model type that implements IReducerModel
.
Required Methods
IReducer<T>
requires implementing two key methods:
Method | Purpose | Parameters |
---|---|---|
RollForwardAsync | Called when new blocks are discovered, allowing you to extract and store blockchain data. | Block object |
RollBackwardAsync | Called during chain rollbacks, enabling you to remove or update data from blocks that are no longer part of the canonical chain. | ulong slot |
By implementing these methods, your reducer actively tracks the evolving state of the blockchain. Together, they provide a robust mechanism to keep your database synchronized with the canonical chain, enabling reliable and up-to-date blockchain data management.
5. Configure Application Settings
Argus requires specific configuration settings to connect to a Cardano node and manage synchronization. Create an appsettings.json
file with the following key sections:
- ConnectionStrings: Database connection information
- CardanoNodeConnection: Settings for connecting to the Cardano node
- Sync: Configuration for the synchronization process
For detailed explanation of all configuration options, see the Configuration Guide.
{
"ConnectionStrings": {
"CardanoContext": "Host=localhost;Database=argus;Username=postgres;Password=password;Port=5432",
"CardanoContextSchema": "cardanoindexer"
},
"CardanoNodeConnection": {
"ConnectionType": "UnixSocket",
"UnixSocket": {
"Path": "/path/to/node.socket"
},
"NetworkMagic": 764824073,
"MaxRollbackSlots": 1000,
"RollbackBuffer": 10,
"Slot": 139522569,
"Hash": "3fd9925888302fca267c580d8fe6ebc923380d0b984523a1dfbefe88ef089b66"
},
"Sync": {
"Dashboard": {
"TuiMode": true,
"RefreshInterval": 5000,
"DisplayType": "sync"
}
}
}
Argus supports multiple connection methods:
- UnixSocket: Direct connection to a local node (fastest option)
- gRPC: Connection to a remote node via UtxoRPC (easiest to set up)
- TCP: Network connection to a remote node (traditional approach)
Choose the option that works best for your environment.
6. Register Services
Register Argus services in your Program.cs
:
using Argus.Sync.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Register Argus services
builder.Services.AddCardanoIndexer<MyDbContext>(builder.Configuration);
builder.Services.AddReducers<MyDbContext, IReducerModel>(builder.Configuration);
var app = builder.Build();
app.Run();
Extension Methods
These two extension methods connect all the components you've created:
Method | Purpose |
---|---|
AddCardanoIndexer | Configures database connection, node connection, and synchronization services |
AddReducers | Registers your reducers and connects them to your data models |
These methods automate the wiring of components, allowing you to focus on your custom data models and reducers rather than infrastructure setup.
7. Create and Apply Migrations
Generate and apply Entity Framework migrations:
# Create the initial migration
dotnet ef migrations add InitialMigration
# Apply the migration to the database
dotnet ef database update
Ensure your PostgreSQL server is running and accessible with the credentials specified in your connection string before running these commands.
8. Run Your Application
Start your application to begin synchronizing with the blockchain:
dotnet run
When your application starts, you'll see the Argus dashboard in your terminal showing synchronization progress. Initial synchronization from the genesis block can take substantial time, so consider starting from a more recent block using the Slot
and Hash
settings in your configuration.
Argus Integration Best Practices
Effective Reducer Design
Use slot-based tracking:
// Store the slot with each record for rollback support
public record TokenTransfer(
string TxHash,
int TxIndex,
ulong Slot, // Critical for chain rollback handling
string PolicyId,
string AssetName,
string FromAddress,
string ToAddress,
ulong Amount,
ulong Lovelace
) : IReducerModel;
Storing the block slot with each record is essential for Argus's chain rollback handling:
- Slot numbers uniquely identify blockchain positions
- During rollbacks, Argus provides the exact slot to roll back to
- All records with slots greater than the rollback point must be reversed
Storing the block slot with each record is crucial for Argus’s effective chain rollback management, as slot numbers uniquely mark blockchain positions. This allows Argus to precisely identify rollback points and reverse all records from slots beyond the rollback, ensuring accurate state restoration.
Maintain data integrity with Argus’s transactional processing:
public async Task RollForwardAsync(Block block)
{
using var db = dbContextFactory.CreateDbContext();
// Process all operations within the same transaction
foreach (var tx in block.TransactionBodies())
{
ProcessInputs(db, tx);
ProcessOutputs(db, tx);
ProcessMetadata(db, tx);
}
await db.SaveChangesAsync();
}
Argus provides important transaction guarantees:
- Each block is processed in an isolated transaction
- All your reducers are synchronized to maintain cross-entity consistency
Argus ensures robust transaction guarantees by processing each block within an isolated transaction and synchronizing all reducers to maintain consistent state across multiple entities. This approach provides reliable and consistent data handling essential for blockchain applications.
Argus-Specific Data Patterns
Use active-historical architecture for Cardano's UTxO model:
// Active state
public class ActiveUtxo
{
public string TxHash { get; set; } // Transaction hash
public int Index { get; set; } // Output index
public string Address { get; set; } // Owner address
public long Lovelace { get; set; } // ADA amount in lovelace
public string[] Assets { get; set; } // Native tokens
public ulong Slot { get; set; } // Block slot
}
// Historical state
public class HistoricalUtxo
{
public string TxHash { get; set; }
public int Index { get; set; }
public string OutRef { get; set; } // Consumed UTxO
public string Address { get; set; }
public long Lovelace { get; set; }
public string[] Assets { get; set; }
public ulong Slot { get; set; }
}
This dual-state approach aligns perfectly with Cardano's UTxO model:
- Active State: Tracks the current UTxO (Unspent Transaction Output)
- History State: Records a transaction that has been executed
This dual-state approach complements Cardano’s UTxO model by maintaining an Active State for tracking current unspent outputs and a History State for recording completed transactions, ensuring accurate and efficient ledger management.