Skip to content

Commit

Permalink
Added a IEnumerable<IIndexEvent> ParseTransaction(Block block, int tr…
Browse files Browse the repository at this point in the history
…ansactionIndex, Transaction transaction) parse transaction method
  • Loading branch information
jaensen committed Sep 2, 2024
1 parent 13be2c7 commit ce5d81b
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 29 deletions.
7 changes: 6 additions & 1 deletion Circles.Index.CirclesV1/LogParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ public class LogParser(Address v1HubAddress) : ILogParser
private readonly Hash256 _hubTransferTopic = new(DatabaseSchema.HubTransfer.Topic);
private readonly Hash256 _trustTopic = new(DatabaseSchema.Trust.Topic);

public IEnumerable<IIndexEvent> ParseLog(Block block, TxReceipt receipt, LogEntry log, int logIndex)
public IEnumerable<IIndexEvent> ParseTransaction(Block block, int transactionIndex, Transaction transaction)
{
return Enumerable.Empty<IIndexEvent>();
}

public IEnumerable<IIndexEvent> ParseLog(Block block, Transaction transaction, TxReceipt receipt, LogEntry log, int logIndex)
{
List<IIndexEvent> events = new();
if (log.Topics.Length == 0)
Expand Down
7 changes: 6 additions & 1 deletion Circles.Index.CirclesV2.NameRegistry/LogParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ public class LogParser(Address nameRegistryAddress) : ILogParser
private readonly Hash256 _updateMetadataDigestTopic = new(DatabaseSchema.UpdateMetadataDigest.Topic);
private readonly Hash256 _cidV0Topic = new(DatabaseSchema.CidV0.Topic);

public IEnumerable<IIndexEvent> ParseLog(Block block, TxReceipt receipt, LogEntry log, int logIndex)
public IEnumerable<IIndexEvent> ParseTransaction(Block block, int transactionIndex, Transaction transaction)
{
return Enumerable.Empty<IIndexEvent>();
}

public IEnumerable<IIndexEvent> ParseLog(Block block, Transaction transaction, TxReceipt receipt, LogEntry log, int logIndex)
{
if (log.Topics.Length == 0)
{
Expand Down
7 changes: 6 additions & 1 deletion Circles.Index.CirclesV2.StandardTreasury/LogParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ public class LogParser(Address standardTreasuryAddress) : ILogParser
private readonly Hash256 _groupRedeemCollateralReturnTopic = new(DatabaseSchema.GroupRedeemCollateralReturn.Topic);
private readonly Hash256 _groupRedeemCollateralBurnTopic = new(DatabaseSchema.GroupRedeemCollateralBurn.Topic);

public IEnumerable<IIndexEvent> ParseLog(Block block, TxReceipt receipt, LogEntry log, int logIndex)
public IEnumerable<IIndexEvent> ParseTransaction(Block block, int transactionIndex, Transaction transaction)
{
return Enumerable.Empty<IIndexEvent>();
}

public IEnumerable<IIndexEvent> ParseLog(Block block, Transaction transaction, TxReceipt receipt, LogEntry log, int logIndex)
{
if (log.Topics.Length == 0)
{
Expand Down
81 changes: 57 additions & 24 deletions Circles.Index.CirclesV2/LogParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ namespace Circles.Index.CirclesV2;
public class LogParser(Address v2HubAddress) : ILogParser
{
private readonly Hash256 _stoppedTopic = new(DatabaseSchema.Stopped.Topic);

private readonly Hash256 _trustTopic = new(DatabaseSchema.Trust.Topic);
private readonly Hash256 _inviteHumanTopic = new(DatabaseSchema.InviteHuman.Topic);

// private readonly Hash256 _inviteHumanTopic = new(DatabaseSchema.InviteHuman.Topic);
private readonly Hash256 _personalMintTopic = new(DatabaseSchema.PersonalMint.Topic);
private readonly Hash256 _registerHumanTopic = new(DatabaseSchema.RegisterHuman.Topic);
private readonly Hash256 _registerGroupTopic = new(DatabaseSchema.RegisterGroup.Topic);
Expand All @@ -32,7 +34,60 @@ public class LogParser(Address v2HubAddress) : ILogParser

public static readonly ConcurrentDictionary<Address, object?> Erc20WrapperAddresses = new();

public IEnumerable<IIndexEvent> ParseLog(Block block, TxReceipt receipt, LogEntry log, int logIndex)
private readonly byte[] _registerHumanFunctionSignature =
Keccak.Compute("registerHuman(address,bytes32)").Bytes[..4].ToArray();

public IEnumerable<IIndexEvent> ParseTransaction(Block block, int transactionIndex, Transaction transaction)
{
if (transaction.To != v2HubAddress)
{
yield break;
}

if (transaction.Data == null || transaction.Data.Value.Length < 68)
{
// 68 is the size of a complete registerHuman call with arguments
yield break;
}

Console.WriteLine($"Parsing tx {transaction.Hash}. Data length: {transaction.Data.Value.Length}");

// Parse the whole call data for a `registerHuman` call to get the inviter address and
// create a InviteHuman event from it.
// TODO: This is only for v0.3.6 and will be replace with an additional parameter on the InviteHuman event in the next version
// Because we cannot know how the contract was called (e.g. via a safe), we simply search for the function signature.
int callLength = 4;
for (int i = 0; i < transaction.Data.Value.Length - callLength; i++)
{
if (!transaction.Data.Value[i..(i + 4)].Span.SequenceEqual(_registerHumanFunctionSignature))
{
continue;
}

// Extract the bytes for the following call signature:
// function registerHuman(address _inviter, bytes32 _metadataDigest) external
var inviterAddressOffset = i + callLength;
var inviterAddressWithoutPaddingOffset = inviterAddressOffset + 12;
var inviterAddress = new Address(transaction.Data.Value[inviterAddressWithoutPaddingOffset..
(inviterAddressWithoutPaddingOffset + 20)].ToArray());

// TODO: Usually the sender is the invitee, but if the call comes e.g. from a safe, this is no necessarily true.
var invitee = transaction.SenderAddress!;
if (inviterAddress == Address.Zero)
{
break;
}

yield return new InviteHuman(block.Number, (long)block.Timestamp, transactionIndex, -1,
transaction.Hash!.ToString(),
inviterAddress.ToString(), invitee.ToString());

break;
}
}

public IEnumerable<IIndexEvent> ParseLog(Block block, Transaction transaction, TxReceipt receipt, LogEntry log,
int logIndex)
{
if (log.Topics.Length == 0)
{
Expand All @@ -53,11 +108,6 @@ public IEnumerable<IIndexEvent> ParseLog(Block block, TxReceipt receipt, LogEntr
yield return CrcV2Trust(block, receipt, log, logIndex);
}

if (topic == _inviteHumanTopic)
{
yield return CrcV2InviteHuman(block, receipt, log, logIndex);
}

if (topic == _personalMintTopic)
{
yield return CrcV2PersonalMint(block, receipt, log, logIndex);
Expand Down Expand Up @@ -317,23 +367,6 @@ private PersonalMint CrcV2PersonalMint(Block block, TxReceipt receipt, LogEntry
endPeriod);
}

private InviteHuman CrcV2InviteHuman(Block block, TxReceipt receipt, LogEntry log, int logIndex)
{
string inviterAddress =
"0x" + log.Topics[1].ToString().Substring(Consts.AddressEmptyBytesPrefixLength);
string inviteeAddress =
"0x" + log.Topics[2].ToString().Substring(Consts.AddressEmptyBytesPrefixLength);

return new InviteHuman(
block.Number,
(long)block.Timestamp,
receipt.Index,
logIndex,
receipt.TxHash!.ToString(),
inviterAddress,
inviteeAddress);
}

private Trust CrcV2Trust(Block block, TxReceipt receipt, LogEntry log, int logIndex)
{
string userAddress = "0x" + log.Topics[1].ToString().Substring(Consts.AddressEmptyBytesPrefixLength);
Expand Down
5 changes: 4 additions & 1 deletion Circles.Index.Common/ILogParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ namespace Circles.Index.Common;

public interface ILogParser
{
IEnumerable<IIndexEvent> ParseLog(Block block, TxReceipt receipt, LogEntry log, int logIndex);
IEnumerable<IIndexEvent> ParseTransaction(Block block, int transactionIndex, Transaction transaction);

IEnumerable<IIndexEvent> ParseLog(Block block, Transaction transaction, TxReceipt receipt, LogEntry log,
int logIndex);
}
40 changes: 39 additions & 1 deletion Circles.Index/BlockIndexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Nethermind.Blockchain;
using Nethermind.Blockchain.Receipts;
using Nethermind.Core;
using Nethermind.Core.Crypto;

namespace Circles.Index;

Expand Down Expand Up @@ -96,6 +97,19 @@ private async Task Sink((BlockWithReceipts, IEnumerable<IIndexEvent>) data)
TransformBlock<BlockWithReceipts, (BlockWithReceipts, IEnumerable<IIndexEvent>)> parserBlock = new(
blockWithReceipts =>
{
Dictionary<Hash256, Transaction> transactionsByHash = new();
Dictionary<Hash256, int> transactionIndexByHash = new();

for (var i = 0; i < blockWithReceipts.Block.Transactions.Length; i++)
{
var tx = blockWithReceipts.Block.Transactions[i];
if (tx.Hash != null)
{
transactionsByHash[tx.Hash] = tx;
transactionIndexByHash[tx.Hash] = i;
}
}

List<IIndexEvent> events = [];
foreach (var receipt in blockWithReceipts.Receipts)
{
Expand All @@ -105,14 +119,38 @@ private async Task Sink((BlockWithReceipts, IEnumerable<IIndexEvent>) data)
return (blockWithReceipts, events);
}

var transaction = transactionsByHash[receipt.TxHash!];
var transactionIndex = transactionIndexByHash[receipt.TxHash!];
try
{
foreach (var parser in context.LogParsers)
{
var parsedEvents = parser.ParseTransaction(blockWithReceipts.Block,
transactionIndex, transaction);

events.AddRange(parsedEvents);
}
}
catch (Exception e)
{
context.Logger.Error($"Error parsing transaction {transaction}");
context.Logger.Error($"Block: {blockWithReceipts.Block.Number}");
context.Logger.Error($"Receipt.TxHash: {receipt.TxHash}");
context.Logger.Error(e.Message);
context.Logger.Error(e.StackTrace);
throw;
}

for (int i = 0; i < receipt.Logs?.Length; i++)
{
LogEntry log = receipt.Logs[i];
foreach (var parser in context.LogParsers)
{
try
{
var parsedEvents = parser.ParseLog(blockWithReceipts.Block, receipt, log, i);
var parsedEvents = parser.ParseLog(blockWithReceipts.Block,
transaction, receipt, log, i);

events.AddRange(parsedEvents);
}
catch (Exception e)
Expand Down

0 comments on commit ce5d81b

Please sign in to comment.