Skip to content

Commit

Permalink
feat: basic utxo indexer example and minor updates to support sundae …
Browse files Browse the repository at this point in the history
…swap liquidity pool query (#35)
  • Loading branch information
Mercurial authored Sep 10, 2024
1 parent ffc54b1 commit a36d326
Show file tree
Hide file tree
Showing 16 changed files with 479 additions and 33 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/scripts/*.csv
/scripts/*.log
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"files.watcherExclude": {
"**/target": true
}
}
4 changes: 2 additions & 2 deletions extension/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ pg_test = []
# pallas = "0.21"
pallas = { git = "https://github.com/txpipe/pallas.git" }
pgrx = "=0.11.3"
serde_json = "1.0.114"
serde = "1.0.197"
serde_json = "1.0.128"
serde = "1.0.209"
hex = "0.4.3"
bech32 = "0.9.1"
chrono = "0.4.38"
Expand Down
69 changes: 38 additions & 31 deletions extension/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ fn tx_outputs(
'static,
(
name!(output_index, i32),
name!(address, String),
name!(address, Option<String>),
name!(lovelace, pgrx::AnyNumeric),
name!(assets, pgrx::Json),
name!(datum, pgrx::Json),
Expand All @@ -215,10 +215,7 @@ fn tx_outputs(
.map(|(i, o)| {
(
i as i32,
match o.address() {
Ok(addr) => addr.to_string(),
Err(_) => "ERROR PARSING ADDRESS".to_string(),
},
output_to_address_string(o),
AnyNumeric::from(o.lovelace_amount()),
pgrx::Json(
serde_json::to_value(
Expand Down Expand Up @@ -270,10 +267,7 @@ fn tx_outputs_json(tx_cbor: &[u8]) -> pgrx::JsonB {
.map(|(i, o)| {
serde_json::json!({
"output_index": i as i32,
"address": match o.address() {
Ok(addr) => addr.to_string(),
Err(_) => "ERROR PARSING ADDRESS".to_string(),
},
"address": output_to_address_string(o),
"lovelace": o.lovelace_amount().to_string(),
"assets": o.non_ada_assets()
.iter()
Expand Down Expand Up @@ -314,7 +308,7 @@ fn tx_addresses(tx_cbor: &[u8]) -> Vec<Option<String>> {
let outputs_data = tx
.outputs()
.iter()
.map(|o| o.address().ok().map(|addr| addr.to_string()))
.map(|o| output_to_address_string(o))
.collect::<Vec<_>>();

outputs_data
Expand Down Expand Up @@ -362,10 +356,10 @@ fn tx_fee(tx_cbor: &[u8]) -> pgrx::AnyNumeric {
}

#[pg_extern(immutable)]
fn tx_mint(tx_cbor: &[u8]) -> pgrx::JsonB {
fn tx_mint(tx_cbor: &[u8]) -> Option<pgrx::JsonB> {
let tx = match MultiEraTx::decode(tx_cbor) {
Ok(x) => x,
Err(_) => return pgrx::JsonB(serde_json::json!(null)),
Err(_) => return None,
};

let mints = tx.mints();
Expand All @@ -384,7 +378,11 @@ fn tx_mint(tx_cbor: &[u8]) -> pgrx::JsonB {
})
.collect();

pgrx::JsonB(serde_json::json!(mint_data))
if mint_data.is_empty() {
return None;
}

Some(pgrx::JsonB(serde_json::json!(mint_data)))
}

#[pg_extern(immutable)]
Expand Down Expand Up @@ -615,7 +613,7 @@ fn address_payment_part(address: &[u8]) -> Vec<u8> {

let payment_part = match address {
Address::Shelley(a) => a.payment().to_vec(),
Address::Byron(a) => {
Address::Byron(_) => {
vec![]
}
_ => return vec![],
Expand All @@ -633,7 +631,7 @@ fn address_stake_part(address: &[u8]) -> Vec<u8> {

let stake_part = match address {
Address::Shelley(a) => a.delegation().to_vec(),
Address::Byron(a) => {
Address::Byron(_) => {
vec![]
}
_ => return vec![],
Expand Down Expand Up @@ -903,25 +901,19 @@ fn utxo_subject_amount(era: i32, utxo_cbor: &[u8], subject: &[u8]) -> pgrx::AnyN
}

#[pg_extern(immutable)]
fn utxo_plutus_data(era: i32, utxo_cbor: &[u8]) -> pgrx::Json {
let era_enum = match pallas::ledger::traverse::Era::from_int(era) {
Some(x) => x,
None => return pgrx::Json(serde_json::json!(null)),
};
fn utxo_plutus_data(era: i32, utxo_cbor: &[u8]) -> Option<pgrx::Json> {
let era_enum = pallas::ledger::traverse::Era::from_int(era)?;

let output = match MultiEraOutput::decode(era_enum, utxo_cbor) {
Ok(x) => x,
Err(_) => return pgrx::Json(serde_json::json!(null)),
};
let output = MultiEraOutput::decode(era_enum, utxo_cbor).ok()?;

match output.datum().unwrap() {
pallas::ledger::primitives::conway::PseudoDatumOption::Hash(_) => {
pgrx::Json(serde_json::json!(null))
}
pallas::ledger::primitives::conway::PseudoDatumOption::Data(d) => {
pgrx::Json(d.unwrap().deref().to_json())
output.datum().and_then(|datum_option| {
match datum_option {
pallas::ledger::primitives::conway::PseudoDatumOption::Hash(_) => None,
pallas::ledger::primitives::conway::PseudoDatumOption::Data(d) => {
Some(pgrx::Json(d.deref().to_json()))
}
}
}
})
}

#[pg_extern(immutable)]
Expand All @@ -940,6 +932,21 @@ fn from_bech32(bech32: &str) -> Vec<u8> {
}
}

fn output_to_address_string(output: &MultiEraOutput) -> Option<String> {
match output.address() {
Ok(addr) => {
let addr_str = addr.to_string();
// Truncate the address to 103 characters typical HEADER, PAYMENT PART and DELEGATION PART encoding in bech32
if addr_str.len() > 103 {
Some(addr_str[..103].to_string())
} else {
Some(addr_str)
}
}
Err(_) => None,
}
}

#[cfg(any(test, feature = "pg_test"))]
#[pg_schema]
mod tests {
Expand Down
2 changes: 2 additions & 0 deletions indexer/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bin
obj
39 changes: 39 additions & 0 deletions indexer/Data/MumakDbContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Cardano.Sync.Data;
using Cardano.Sync.Data.Models;
using Cardano.Sync.Reducers;
using Microsoft.EntityFrameworkCore;

namespace Mumak.Indexer.Data;

public class MumakDbContext
(
DbContextOptions<MumakDbContext> options,
IConfiguration configuration
) : CardanoDbContext(options, configuration)
{
public DbSet<Utxo> Utxos { get; set; }

override protected void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<Utxo>(entity =>
{
entity.ToTable("utxos");
entity.HasKey(e => new { e.Slot, e.Id, e.TxIndex });
entity.Property(e => e.Id)
.HasColumnName("id");
entity.Property(e => e.TxIndex)
.HasColumnName("tx_index");
entity.Property(e => e.Slot)
.HasColumnName("slot");
entity.Property(e => e.Raw)
.HasColumnName("raw");
});
}
}
10 changes: 10 additions & 0 deletions indexer/Data/Utxo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Cardano.Sync.Data.Models;

namespace Mumak.Indexer.Data;

public record Utxo(
string Id,
ulong TxIndex,
ulong Slot,
byte[] Raw
) : IReducerModel;
71 changes: 71 additions & 0 deletions indexer/Migrations/20240910100707_InitialCreate.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions indexer/Migrations/20240910100707_InitialCreate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace Mumak.Indexer.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.EnsureSchema(
name: "public");

migrationBuilder.CreateTable(
name: "ReducerStates",
schema: "public",
columns: table => new
{
Name = table.Column<string>(type: "text", nullable: false),
Slot = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
Hash = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ReducerStates", x => x.Name);
});

migrationBuilder.CreateTable(
name: "utxos",
schema: "public",
columns: table => new
{
id = table.Column<string>(type: "text", nullable: false),
tx_index = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
slot = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
raw = table.Column<byte[]>(type: "bytea", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_utxos", x => new { x.slot, x.id, x.tx_index });
});
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ReducerStates",
schema: "public");

migrationBuilder.DropTable(
name: "utxos",
schema: "public");
}
}
}
Loading

0 comments on commit a36d326

Please sign in to comment.