Skip to content

Commit

Permalink
Store events simple log processor, TableRepository (InMemory), Store …
Browse files Browse the repository at this point in the history
…tables and supporting methods (decode schema, fields etc), generic fixes and refactoring
  • Loading branch information
juanfranblanco committed Apr 24, 2024
1 parent 3bcb0dc commit 92b8649
Show file tree
Hide file tree
Showing 41 changed files with 1,099 additions and 94 deletions.
4 changes: 0 additions & 4 deletions src/Nethereum.Mud.Contracts/Nethereum.Mud.Contracts.csproj
Expand Up @@ -23,8 +23,4 @@
</None>
</ItemGroup>

<ItemGroup>
<Folder Include="StoreEvents\" />
</ItemGroup>

</Project>
75 changes: 75 additions & 0 deletions src/Nethereum.Mud.Contracts/StoreEvents/StoreEvents.cs
@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nethereum.ABI.FunctionEncoding.Attributes;

namespace Nethereum.Mud.Contracts.StoreEvents
{
public partial class StoreDeleteRecordEventDTO : StoreDeleteRecordEventDTOBase { }

[Event("Store_DeleteRecord")]
public class StoreDeleteRecordEventDTOBase : IEventDTO
{
[Parameter("bytes32", "tableId", 1, true)]
public virtual byte[] TableId { get; set; }
[Parameter("bytes32[]", "keyTuple", 2, false)]
public virtual List<byte[]> KeyTuple { get; set; }
}

public partial class StoreSpliceStaticDataEventDTO : StoreSpliceStaticDataEventDTOBase { }

[Event("Store_SpliceStaticData")]
public class StoreSpliceStaticDataEventDTOBase : IEventDTO
{
[Parameter("bytes32", "tableId", 1, true)]
public virtual byte[] TableId { get; set; }
[Parameter("bytes32[]", "keyTuple", 2, false)]
public virtual List<byte[]> KeyTuple { get; set; }
[Parameter("uint48", "start", 3, false)]
public virtual ulong Start { get; set; }
[Parameter("bytes", "data", 4, false)]
public virtual byte[] Data { get; set; }
}

public partial class StoreSetRecordEventDTO : StoreSetRecordEventDTOBase { }

[Event("Store_SetRecord")]
public class StoreSetRecordEventDTOBase : IEventDTO
{
[Parameter("bytes32", "tableId", 1, true)]
public virtual byte[] TableId { get; set; }
[Parameter("bytes32[]", "keyTuple", 2, false)]
public virtual List<byte[]> KeyTuple { get; set; }
[Parameter("bytes", "staticData", 3, false)]
public virtual byte[] StaticData { get; set; }
[Parameter("bytes32", "encodedLengths", 4, false)]
public virtual byte[] EncodedLengths { get; set; }
[Parameter("bytes", "dynamicData", 5, false)]
public virtual byte[] DynamicData { get; set; }
}


public partial class StoreSpliceDynamicDataEventDTO : StoreSpliceDynamicDataEventDTOBase { }
[Event("Store_SpliceDynamicData")]
public class StoreSpliceDynamicDataEventDTOBase : IEventDTO
{
[Parameter("bytes32", "tableId", 1, true)]
public virtual byte[] TableId { get; set; }
[Parameter("bytes32[]", "keyTuple", 2, false)]
public virtual List<byte[]> KeyTuple { get; set; }
[Parameter("uint8", "dynamicFieldIndex", 3, false)]
public virtual byte DynamicFieldIndex { get; set; }
[Parameter("uint48", "start", 4, false)]
public virtual ulong Start { get; set; }
[Parameter("uint40", "deleteCount", 5, false)]
public virtual ulong DeleteCount { get; set; }
[Parameter("bytes32", "encodedLengths", 6, false)]
public virtual byte[] EncodedLengths { get; set; }
[Parameter("bytes", "data", 7, false)]
public virtual byte[] Data { get; set; }
}


}
193 changes: 193 additions & 0 deletions src/Nethereum.Mud.Contracts/StoreEvents/StoreEventsLogProcessing.cs
@@ -0,0 +1,193 @@
using Nethereum.BlockchainProcessing.Services;
using Nethereum.Web3;
using Nethereum.Contracts.Services;
using System.Numerics;
using Nethereum.Contracts;
using Nethereum.RPC.Eth.DTOs;
using Nethereum.Mud.TableRepository;
using Nethereum.Mud.EncodingDecoding;
using Nethereum.ABI;
using Nethereum.ABI.Encoders;
using Nethereum.Hex.HexConvertors.Extensions;


namespace Nethereum.Mud.Contracts.StoreEvents
{
public class StoreEventsLogProcessing
{
private readonly IBlockchainLogProcessingService _blockchainLogProcessing;
private readonly IEthApiContractService _ethApiContractService;

public StoreEventsLogProcessing(IWeb3 web3)
{
_blockchainLogProcessing = web3.Processing.Logs;
_ethApiContractService = web3.Eth;
}

public Task<List<EventLog<StoreSetRecordEventDTO>>> GetAllSetRecordForContract(string contractAddress,
BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest,
int retryWeight = BlockchainLogProcessingService.RetryWeight)
{
return _blockchainLogProcessing.GetAllEventsForContracts<StoreSetRecordEventDTO>(contractAddresses: new[] { contractAddress }, fromBlockNumber, toBlockNumber,
cancellationToken, numberOfBlocksPerRequest, retryWeight);
}

public async Task<List<EventLog<StoreSetRecordEventDTO>>> GetAllSetRecordForTableAndContract(string contractAddress, byte[] tableId,
BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest,
int retryWeight = BlockchainLogProcessingService.RetryWeight)

{
var filterInputTo = new FilterInputBuilder<StoreSetRecordEventDTO>().AddTopic(x => x.TableId, tableId)
.Build(contractAddress);
return await _blockchainLogProcessing.GetAllEvents<StoreSetRecordEventDTO>(filterInputTo, fromBlockNumber, toBlockNumber,
cancellationToken, numberOfBlocksPerRequest, retryWeight).ConfigureAwait(false);


}

public async Task<List<EventLog<StoreSetRecordEventDTO>>> GetAllSetRecordForTableAndContract(string contractAddress, string nameSpace, string tableName,
BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest,
int retryWeight = BlockchainLogProcessingService.RetryWeight)

{
var tableId = ResourceEncoder.EncodeTable(nameSpace, tableName);
return await GetAllSetRecordForTableAndContract(contractAddress, tableId, fromBlockNumber, toBlockNumber, cancellationToken, numberOfBlocksPerRequest, retryWeight);

}

public async Task<List<EventLog<StoreSetRecordEventDTO>>> GetAllSetRecordForTableAndContract(string contractAddress, string tableName,
BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest,
int retryWeight = BlockchainLogProcessingService.RetryWeight)

{
var tableId = ResourceEncoder.EncodeRootTable(tableName);
return await GetAllSetRecordForTableAndContract(contractAddress, tableId, fromBlockNumber, toBlockNumber, cancellationToken, numberOfBlocksPerRequest, retryWeight);

}

public Task<List<EventLog<StoreSpliceStaticDataEventDTO>>> GetAllSpliceStaticDataForContract(string contractAddress,
BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest,
int retryWeight = BlockchainLogProcessingService.RetryWeight)
{
return _blockchainLogProcessing.GetAllEventsForContracts<StoreSpliceStaticDataEventDTO>(contractAddresses: new[] { contractAddress }, fromBlockNumber, toBlockNumber,
cancellationToken, numberOfBlocksPerRequest, retryWeight);
}

public async Task<List<EventLog<StoreSpliceStaticDataEventDTO>>> GetAllSpliceStaticDataForTableAndContract(string contractAddress, byte[] tableId,
BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest,
int retryWeight = BlockchainLogProcessingService.RetryWeight)

{
var filterInputTo = new FilterInputBuilder<StoreSetRecordEventDTO>().AddTopic(x => x.TableId, tableId)
.Build(contractAddress);
return await _blockchainLogProcessing.GetAllEvents<StoreSpliceStaticDataEventDTO>(filterInputTo, fromBlockNumber, toBlockNumber,
cancellationToken, numberOfBlocksPerRequest, retryWeight).ConfigureAwait(false);
}

public async Task<List<EventLog<StoreSpliceStaticDataEventDTO>>> GetAllSpliceStaticDataForTableAndContract(string contractAddress, string nameSpace, string tableName,
BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest,
int retryWeight = BlockchainLogProcessingService.RetryWeight)

{
var tableId = ResourceEncoder.EncodeTable(nameSpace, tableName);
return await GetAllSpliceStaticDataForTableAndContract(contractAddress, tableId, fromBlockNumber, toBlockNumber, cancellationToken, numberOfBlocksPerRequest, retryWeight);

}

public async Task<List<EventLog<StoreSpliceStaticDataEventDTO>>> GetAllSpliceStaticDataForTableAndContract(string contractAddress, string tableName,
BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest,
int retryWeight = BlockchainLogProcessingService.RetryWeight)

{
var tableId = ResourceEncoder.EncodeRootTable(tableName);
return await GetAllSpliceStaticDataForTableAndContract(contractAddress, tableId, fromBlockNumber, toBlockNumber, cancellationToken, numberOfBlocksPerRequest, retryWeight);

}


public async Task ProcessAllStoreChangesAsync(ITableRepository tableRepository, string contractAddress, BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest,
int retryWeight = BlockchainLogProcessingService.RetryWeight)
{
var topics = new List<object>
{
Event<StoreSetRecordEventDTO>.GetEventABI().GetTopicBuilder().GetSignatureTopic(),
Event<StoreSpliceStaticDataEventDTO>.GetEventABI().GetTopicBuilder().GetSignatureTopic(),
Event<StoreSpliceDynamicDataEventDTO>.GetEventABI().GetTopicBuilder().GetSignatureTopic(),
Event<StoreDeleteRecordEventDTO>.GetEventABI().GetTopicBuilder().GetSignatureTopic()
};

var filterInput = new NewFilterInput()
{
Address = new[] { contractAddress },
Topics = new object[] { topics.ToArray() }
};

await ProcessAllStoreChangesAsync(tableRepository, fromBlockNumber, toBlockNumber, numberOfBlocksPerRequest, retryWeight, filterInput, cancellationToken);

}

public async Task ProcessAllStoreChangesAsync(ITableRepository tableRepository, string contractAddress, string nameSpace, string tableName, BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest,
int retryWeight = BlockchainLogProcessingService.RetryWeight)
{
var tableId = ResourceEncoder.EncodeTable(nameSpace, tableName);
await ProcessAllStoreChangesAsync(tableRepository, contractAddress, tableId, fromBlockNumber, toBlockNumber, cancellationToken, numberOfBlocksPerRequest, retryWeight);
}

public async Task ProcessAllStoreChangesAsync(ITableRepository tableRepository, string contractAddress, string tableName, BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest,
int retryWeight = BlockchainLogProcessingService.RetryWeight)
{
var tableId = ResourceEncoder.EncodeRootTable(tableName);
await ProcessAllStoreChangesAsync(tableRepository, contractAddress, tableId, fromBlockNumber, toBlockNumber, cancellationToken, numberOfBlocksPerRequest, retryWeight);
}

public async Task ProcessAllStoreChangesAsync(ITableRepository tableRepository, string contractAddress, byte[] tableId, BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest,
int retryWeight = BlockchainLogProcessingService.RetryWeight)
{
var topics = new List<object>
{
Event<StoreSetRecordEventDTO>.GetEventABI().GetTopicBuilder().GetSignatureTopic(),
Event<StoreSpliceStaticDataEventDTO>.GetEventABI().GetTopicBuilder().GetSignatureTopic(),
Event<StoreSpliceDynamicDataEventDTO>.GetEventABI().GetTopicBuilder().GetSignatureTopic(),
Event<StoreDeleteRecordEventDTO>.GetEventABI().GetTopicBuilder().GetSignatureTopic()
};

var filterInput = new NewFilterInput()
{
Address = new[] { contractAddress },
Topics = new object[] { topics.ToArray(), new object[] { new Bytes32TypeEncoder().Encode(tableId).ToHex(true) } }
};

await ProcessAllStoreChangesAsync(tableRepository, fromBlockNumber, toBlockNumber, numberOfBlocksPerRequest, retryWeight, filterInput, cancellationToken);
}

private async Task ProcessAllStoreChangesAsync(ITableRepository tableRepository, BigInteger? fromBlockNumber, BigInteger? toBlockNumber, int numberOfBlocksPerRequest, int retryWeight, NewFilterInput filterInput, CancellationToken cancellationToken)
{
var logs = await _blockchainLogProcessing.GetAllEvents(filterInput, fromBlockNumber, toBlockNumber,
cancellationToken, numberOfBlocksPerRequest, retryWeight);

foreach (var log in logs)
{
if (log.IsLogForEvent<StoreSetRecordEventDTO>())
{
var setRecordEventLog = log.DecodeEvent<StoreSetRecordEventDTO>();
var setRecordEvent = setRecordEventLog.Event;
await tableRepository.SetRecordAsync(setRecordEvent.TableId, setRecordEvent.KeyTuple, setRecordEvent.StaticData, setRecordEvent.EncodedLengths, setRecordEvent.DynamicData);
}

if (log.IsLogForEvent<StoreSpliceStaticDataEventDTO>())
{
var spliceStaticDataEventLog = log.DecodeEvent<StoreSpliceStaticDataEventDTO>();
var spliceStaticDataEvent = spliceStaticDataEventLog.Event;
await tableRepository.SetSpliceStaticDataAsync(spliceStaticDataEvent.TableId, spliceStaticDataEvent.KeyTuple, spliceStaticDataEvent.Start, spliceStaticDataEvent.Data);
}

if (log.IsLogForEvent<StoreSpliceDynamicDataEventDTO>())
{
var spliceDynamicDataEventLog = log.DecodeEvent<StoreSpliceDynamicDataEventDTO>();
var spliceDynamicDataEvent = spliceDynamicDataEventLog.Event;
await tableRepository.SetSpliceDynamicDataAsync(spliceDynamicDataEvent.TableId, spliceDynamicDataEvent.KeyTuple, spliceDynamicDataEvent.Start, spliceDynamicDataEvent.Data, spliceDynamicDataEvent.DeleteCount, spliceDynamicDataEvent.EncodedLengths);
}
}
}
}
}
30 changes: 30 additions & 0 deletions src/Nethereum.Mud.Contracts/Tables/Store/ResourceIdsTableRecord.cs
@@ -0,0 +1,30 @@
using Nethereum.ABI.FunctionEncoding.Attributes;
using Nethereum.Mud.EncodingDecoding;
using static Nethereum.Mud.Contracts.Tables.Store.ResourceIdsTableRecord;

namespace Nethereum.Mud.Contracts.Tables.Store
{
public class ResourceIdsTableRecord : TableRecord<ResourceIdsKey, ResourceIdsValue>
{
public ResourceIdsTableRecord() : base("store", "ResourceIds")
{
}

public class ResourceIdsKey
{
[Parameter("bytes32", "resourceId", 1)]
public byte[] ResourceId { get; set; }

public Resource GetResourceIdResource()
{
return ResourceEncoder.Decode(ResourceId);
}
}

public class ResourceIdsValue
{
[Parameter("bool", "exists", 1)]
public bool Exists { get; set; }
}
}
}
35 changes: 35 additions & 0 deletions src/Nethereum.Mud.Contracts/Tables/Store/StoreHooksTableRecord.cs
@@ -0,0 +1,35 @@
using Nethereum.ABI.FunctionEncoding.Attributes;
using Nethereum.Mud.EncodingDecoding;
using System.Threading.Tasks;
using static Nethereum.Mud.Contracts.Tables.Store.StoreHooksTableRecord;

namespace Nethereum.Mud.Contracts.Tables.Store
{
public class StoreHooksTableRecord : TableRecord<StoreHooksKey, StoreHooksValue>
{
public StoreHooksTableRecord() : base("store", "StoreHooks")
{
}

public class StoreHooksKey
{
[Parameter("bytes32", "tableId", 1)]
public byte[] TableId { get; set; }

public Resource GetTableIdResource()
{
return ResourceEncoder.Decode(TableId);
}
}

public class StoreHooksValue
{
[Parameter("bytes21[]", "hooks", 1)]
public List<byte[]> Hooks { get; set; }
}
}
}




@@ -0,0 +1,27 @@
using Nethereum.Mud.Contracts.World;
using Nethereum.RPC.Eth.DTOs;
using static Nethereum.Mud.Contracts.Tables.Store.StoreHooksTableRecord;


namespace Nethereum.Mud.Contracts.Tables.Store
{
public static class StoreHooksWorldServiceExtensions
{
public static async Task<StoreHooksTableRecord> GetStoreHooksTableRecord(this WorldService storeService, StoreHooksKey key, BlockParameter blockParameter = null)
{
var table = new StoreHooksTableRecord();
table.Keys = key;
return await storeService.GetRecordTableQueryAsync<StoreHooksTableRecord, StoreHooksKey, StoreHooksValue>(table, blockParameter);
}

public static async Task<string> SetStoreHooksTableRecordRequestAsync(this WorldService storeService, StoreHooksKey key, List<byte[]> hooks)
{
var table = new StoreHooksTableRecord();
table.Keys = key;
table.Values = new StoreHooksValue() { Hooks = hooks };
return await storeService.SetRecordRequestAsync<StoreHooksKey, StoreHooksValue>(table);
}
}
}


0 comments on commit 92b8649

Please sign in to comment.