Skip to content

Commit

Permalink
Merge pull request #15 from CirclesUBI/feature/circles-get-trust-rela…
Browse files Browse the repository at this point in the history
…tions

Don't serialize numbers as hex when returning a DatabaseQueryResult from rpc
  • Loading branch information
jaensen authored May 18, 2024
2 parents 207d011 + 1d72c9e commit 3d3cb3f
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 26 deletions.
23 changes: 22 additions & 1 deletion Circles.Index.CirclesV2/DatabaseSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,23 @@ public class DatabaseSchema : IDatabaseSchema
new("logIndex", ValueTypes.Int, true),
new("batchIndex", ValueTypes.Int, true, true),
new("transactionHash", ValueTypes.String, true),
new("operatorAddress", ValueTypes.Address, true),
new("operator", ValueTypes.Address, true),
new("fromAddress", ValueTypes.Address, true),
new("toAddress", ValueTypes.Address, true),
new("id", ValueTypes.BigInt, true),
new("value", ValueTypes.BigInt, false)
]);

public static readonly EventSchema TransfersView = new("V_CrcV2", "Transfers",
new byte[32],
[
new("blockNumber", ValueTypes.Int, true),
new("timestamp", ValueTypes.Int, true),
new("transactionIndex", ValueTypes.Int, true),
new("logIndex", ValueTypes.Int, true),
new("batchIndex", ValueTypes.Int, true, true),
new("transactionHash", ValueTypes.String, true),
new("operator", ValueTypes.Address, true),
new("fromAddress", ValueTypes.Address, true),
new("toAddress", ValueTypes.Address, true),
new("id", ValueTypes.BigInt, true),
Expand Down Expand Up @@ -151,6 +167,10 @@ public class DatabaseSchema : IDatabaseSchema
{
("CrcV2", "DiscountCost"),
DiscountCost
},
{
("V_CrcV2", "Transfers"),
TransfersView
}
};

Expand Down Expand Up @@ -289,6 +309,7 @@ public DatabaseSchema()
{ "timestamp", e => e.Timestamp },
{ "transactionIndex", e => e.TransactionIndex },
{ "logIndex", e => e.LogIndex },
{ "batchIndex", e => e.BatchIndex },
{ "transactionHash", e => e.TransactionHash },
{ "operator", e => e.Operator },
{ "from", e => e.From },
Expand Down
66 changes: 65 additions & 1 deletion Circles.Index.Common/IDatabaseQueryResult.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,67 @@
using System.Numerics;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Circles.Index.Common;

public record DatabaseQueryResult(string[] Columns, IEnumerable<object[]> Rows);
[JsonConverter(typeof(DatabaseQueryResultConverter))]
public record DatabaseQueryResult(
string[] Columns,
IEnumerable<object[]> Rows);

public class DatabaseQueryResultConverter : JsonConverter<DatabaseQueryResult>
{
public override DatabaseQueryResult Read(ref Utf8JsonReader reader, Type typeToConvert,
JsonSerializerOptions options)
{
throw new NotImplementedException("Deserialization is not implemented.");
}

public override void Write(Utf8JsonWriter writer, DatabaseQueryResult value, JsonSerializerOptions options)
{
writer.WriteStartObject();

writer.WritePropertyName("Columns");
JsonSerializer.Serialize(writer, value.Columns, options);

writer.WritePropertyName("Rows");
writer.WriteStartArray();
foreach (var row in value.Rows)
{
writer.WriteStartArray();
foreach (var item in row)
{
switch (item)
{
case int i:
writer.WriteNumberValue(i);
break;
case long l:
writer.WriteNumberValue(l);
break;
case float f:
writer.WriteNumberValue(f);
break;
case double d:
writer.WriteNumberValue(d);
break;
case decimal dec:
writer.WriteNumberValue(dec);
break;
case BigInteger bigInt:
writer.WriteStringValue(bigInt.ToString());
break;
default:
JsonSerializer.Serialize(writer, item, options);
break;
}
}

writer.WriteEndArray();
}

writer.WriteEndArray();

writer.WriteEndObject();
}
}
38 changes: 35 additions & 3 deletions Circles.Index.Postgres/PostgresDb.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Data;
using System.Numerics;
using System.Text;
using Circles.Index.Common;
using Nethermind.Core.Crypto;
Expand Down Expand Up @@ -66,6 +67,12 @@ public void Migrate()
}
else
{
if (table.Value.Namespace.StartsWith("V_"))
{
// Dirty way to skip indexes and primary keys for views
continue;
}

primaryKeyDdl.AppendLine(
$"ALTER TABLE \"{table.Value.Namespace}_{table.Value.Table}\" ADD PRIMARY KEY (\"blockNumber\", \"transactionIndex\", \"logIndex\"{additionalKeyColumnsString});");
}
Expand Down Expand Up @@ -138,6 +145,12 @@ private string GetDdl(EventSchema @event)

foreach (var column in indexedColumns)
{
if (@event.Namespace.StartsWith("V_"))
{
// Dirty way to skip indexes and primary keys for views
continue;
}

string indexName = $"idx_{@event.Namespace}_{@event.Table}_{column.Column}";
ddlSql.AppendLine(
$"CREATE INDEX IF NOT EXISTS \"{indexName}\" ON \"{@event.Namespace}_{@event.Table}\" (\"{column.Column}\");");
Expand Down Expand Up @@ -263,20 +276,33 @@ public DatabaseQueryResult Select(ParameterizedSql select)
}

using var reader = command.ExecuteReader();

var resultSchema = reader.GetColumnSchema().ToArray();
var columnNames = new string[reader.FieldCount];
for (int i = 0; i < reader.FieldCount; i++)
{
columnNames[i] = reader.GetName(i);
}

var resultRows = new List<object[]>();
var row = new object[reader.FieldCount];
while (reader.Read())
{
reader.GetValues(row);
for (int i = 0; i < reader.FieldCount; i++)
{
if (resultSchema[i].NpgsqlDbType == NpgsqlDbType.Numeric)
{
row[i] = reader.GetFieldValue<BigInteger>(i);
}
else
{
row[i] = reader.GetValue(i);
}
}

resultRows.Add(row);
}

return new DatabaseQueryResult(columnNames, resultRows);
}

Expand All @@ -295,6 +321,12 @@ public async Task DeleteFromBlockOnwards(long reorgAt)
{
foreach (var table in Schema.Tables.Values)
{
if (table.Namespace.StartsWith("V_"))
{
// Dirty way to skip views
continue;
}

await using var command = connection.CreateCommand();
command.CommandText =
$"DELETE FROM \"{table.Namespace}_{table.Table}\" WHERE \"{"blockNumber"}\" >= @reorgAt;";
Expand Down
2 changes: 1 addition & 1 deletion Circles.Index.Query/Dto/FilterPredicateDtoConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public override void Write(Utf8JsonWriter writer, IFilterPredicateDto value, Jso

public class FilterPredicateArrayConverter : JsonConverter<IFilterPredicateDto[]>
{
public override IFilterPredicateDto[]? Read(ref Utf8JsonReader reader, Type typeToConvert,
public override IFilterPredicateDto[] Read(ref Utf8JsonReader reader, Type typeToConvert,
JsonSerializerOptions options)
{
using JsonDocument document = JsonDocument.ParseValue(ref reader);
Expand Down
27 changes: 17 additions & 10 deletions Circles.Index.Rpc/CirclesRpcModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,10 @@ public Task<ResultWrapper<CirclesTrustRelations>> circles_getTrustRelations(Addr
});

var result = _indexerContext.Database.Select(parameterizedSql);

var incomingTrusts = new List<CirclesTrustRelation>();
var outgoingTrusts = new List<CirclesTrustRelation>();

Console.WriteLine($"result.Rows.Count: {result.Rows.Count()}");


foreach (var resultRow in result.Rows)
{
var user = new Address(resultRow[0].ToString() ?? throw new Exception("A user in the result set is null"));
Expand All @@ -85,6 +83,7 @@ public Task<ResultWrapper<CirclesTrustRelations>> circles_getTrustRelations(Addr
incomingTrusts.Add(new CirclesTrustRelation(user, limit));
}
}

var trustRelations = new CirclesTrustRelations(address, outgoingTrusts.ToArray(), incomingTrusts.ToArray());
return Task.FromResult(ResultWrapper<CirclesTrustRelations>.Success(trustRelations));
}
Expand All @@ -106,13 +105,21 @@ public ResultWrapper<DatabaseQueryResult> circles_query(SelectDto query)
var parameterizedSql = select.ToSql(_indexerContext.Database);
var result = _indexerContext.Database.Select(parameterizedSql);

return ResultWrapper<DatabaseQueryResult>.Success(result);
}
// Log the .net types of the columns of the first row of the result set:
foreach (var resultRow in result.Rows)
{
for (int colIdx = 0; colIdx < resultRow.Length; colIdx++)
{
var colName = result.Columns[colIdx];
var colValue = resultRow[colIdx];

_pluginLogger.Info($"Column '{colName}' is of type '{colValue?.GetType().Name ?? "null"}'");
}

public ResultWrapper<string> circles_computeTransfer(string from, string to, string amount)
{
// string result = LibPathfinder.ffi_compute_transfer(from, to, amount);
return ResultWrapper<string>.Success("");
break;
}

return ResultWrapper<DatabaseQueryResult>.Success(result);
}

#region private methods
Expand Down
4 changes: 0 additions & 4 deletions Circles.Index.Rpc/ICirclesRpcModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,4 @@ public interface ICirclesRpcModule : IRpcModule
[JsonRpcMethod(Description = "Queries the data of one Circles index table",
IsImplemented = true)]
ResultWrapper<DatabaseQueryResult> circles_query(SelectDto query);

[JsonRpcMethod(Description = "Calculates a transitive transfer path along the trust relations of a user",
IsImplemented = true)]
ResultWrapper<string> circles_computeTransfer(string from, string to, string amount);
}
1 change: 1 addition & 0 deletions Circles.sln
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker", "docker", "{B30CB7
deploy.sh = deploy.sh
.gitignore = .gitignore
add-deploy-script-tp-v2-repo.sh = add-deploy-script-tp-v2-repo.sh
example-requests.md = example-requests.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Circles.Index.Postgres", "Circles.Index.Postgres\Circles.Index.Postgres.csproj", "{8ED5FCD0-0995-44E7-9A11-E0EB03BB0832}"
Expand Down
12 changes: 6 additions & 6 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,9 @@ This method allows you to query the total Circles (v1) holdings of an address.
curl -X POST --data '{
"jsonrpc":"2.0",
"method":"circles_getTotalBalance",
"params":["0xde374ece6fa50e781e81aac78e811b33d16912c7"],
"params":["0x2091e2fb4dcfed050adcdd518e57fbfea7e32e5c"],
"id":1
}' -H "Content-Type: application/json" https://circles-rpc.aboutcircles.com/
}' -H "Content-Type: application/json" http://localhost:8545/
````

##### Response:
Expand All @@ -243,9 +243,9 @@ This method allows you to query all individual Circles (v1) holdings of an addre
curl -X POST --data '{
"jsonrpc":"2.0",
"method":"circles_getTokenBalances",
"params":["0xde374ece6fa50e781e81aac78e811b33d16912c7"],
"params":["0x2091e2fb4dcfed050adcdd518e57fbfea7e32e5c"],
"id":1
}' -H "Content-Type: application/json" httpS://circles-rpc.aboutcircles.com/
}' -H "Content-Type: application/json" http://localhost:8545/
```

##### Response:
Expand Down Expand Up @@ -277,9 +277,9 @@ This method allows you to query all (v1) trust relations of an address.
curl -X POST --data '{
"jsonrpc":"2.0",
"method":"circles_getTrustRelations",
"params":["0xde374ece6fa50e781e81aac78e811b33d16912c7"],
"params":["0x2091e2fb4dcfed050adcdd518e57fbfea7e32e5c"],
"id":1
}' -H "Content-Type: application/json" https://circles-rpc.aboutcircles.com/
}' -H "Content-Type: application/json" http://localhost:8545/
````
##### Response:
Expand Down

0 comments on commit 3d3cb3f

Please sign in to comment.