diff --git a/src/Nethereum.Mud.Contracts/Nethereum.Mud.Contracts.csproj b/src/Nethereum.Mud.Contracts/Nethereum.Mud.Contracts.csproj index 77c570b32..99858daec 100644 --- a/src/Nethereum.Mud.Contracts/Nethereum.Mud.Contracts.csproj +++ b/src/Nethereum.Mud.Contracts/Nethereum.Mud.Contracts.csproj @@ -23,8 +23,4 @@ - - - - diff --git a/src/Nethereum.Mud.Contracts/StoreEvents/StoreEvents.cs b/src/Nethereum.Mud.Contracts/StoreEvents/StoreEvents.cs new file mode 100644 index 000000000..128828707 --- /dev/null +++ b/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 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 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 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 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; } + } + + +} diff --git a/src/Nethereum.Mud.Contracts/StoreEvents/StoreEventsLogProcessing.cs b/src/Nethereum.Mud.Contracts/StoreEvents/StoreEventsLogProcessing.cs new file mode 100644 index 000000000..20bde98df --- /dev/null +++ b/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>> GetAllSetRecordForContract(string contractAddress, + BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest, + int retryWeight = BlockchainLogProcessingService.RetryWeight) + { + return _blockchainLogProcessing.GetAllEventsForContracts(contractAddresses: new[] { contractAddress }, fromBlockNumber, toBlockNumber, + cancellationToken, numberOfBlocksPerRequest, retryWeight); + } + + public async Task>> GetAllSetRecordForTableAndContract(string contractAddress, byte[] tableId, + BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest, + int retryWeight = BlockchainLogProcessingService.RetryWeight) + + { + var filterInputTo = new FilterInputBuilder().AddTopic(x => x.TableId, tableId) + .Build(contractAddress); + return await _blockchainLogProcessing.GetAllEvents(filterInputTo, fromBlockNumber, toBlockNumber, + cancellationToken, numberOfBlocksPerRequest, retryWeight).ConfigureAwait(false); + + + } + + public async Task>> 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>> 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>> GetAllSpliceStaticDataForContract(string contractAddress, + BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest, + int retryWeight = BlockchainLogProcessingService.RetryWeight) + { + return _blockchainLogProcessing.GetAllEventsForContracts(contractAddresses: new[] { contractAddress }, fromBlockNumber, toBlockNumber, + cancellationToken, numberOfBlocksPerRequest, retryWeight); + } + + public async Task>> GetAllSpliceStaticDataForTableAndContract(string contractAddress, byte[] tableId, + BigInteger? fromBlockNumber, BigInteger? toBlockNumber, CancellationToken cancellationToken, int numberOfBlocksPerRequest = BlockchainLogProcessingService.DefaultNumberOfBlocksPerRequest, + int retryWeight = BlockchainLogProcessingService.RetryWeight) + + { + var filterInputTo = new FilterInputBuilder().AddTopic(x => x.TableId, tableId) + .Build(contractAddress); + return await _blockchainLogProcessing.GetAllEvents(filterInputTo, fromBlockNumber, toBlockNumber, + cancellationToken, numberOfBlocksPerRequest, retryWeight).ConfigureAwait(false); + } + + public async Task>> 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>> 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 + { + Event.GetEventABI().GetTopicBuilder().GetSignatureTopic(), + Event.GetEventABI().GetTopicBuilder().GetSignatureTopic(), + Event.GetEventABI().GetTopicBuilder().GetSignatureTopic(), + Event.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 + { + Event.GetEventABI().GetTopicBuilder().GetSignatureTopic(), + Event.GetEventABI().GetTopicBuilder().GetSignatureTopic(), + Event.GetEventABI().GetTopicBuilder().GetSignatureTopic(), + Event.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()) + { + var setRecordEventLog = log.DecodeEvent(); + var setRecordEvent = setRecordEventLog.Event; + await tableRepository.SetRecordAsync(setRecordEvent.TableId, setRecordEvent.KeyTuple, setRecordEvent.StaticData, setRecordEvent.EncodedLengths, setRecordEvent.DynamicData); + } + + if (log.IsLogForEvent()) + { + var spliceStaticDataEventLog = log.DecodeEvent(); + var spliceStaticDataEvent = spliceStaticDataEventLog.Event; + await tableRepository.SetSpliceStaticDataAsync(spliceStaticDataEvent.TableId, spliceStaticDataEvent.KeyTuple, spliceStaticDataEvent.Start, spliceStaticDataEvent.Data); + } + + if (log.IsLogForEvent()) + { + var spliceDynamicDataEventLog = log.DecodeEvent(); + var spliceDynamicDataEvent = spliceDynamicDataEventLog.Event; + await tableRepository.SetSpliceDynamicDataAsync(spliceDynamicDataEvent.TableId, spliceDynamicDataEvent.KeyTuple, spliceDynamicDataEvent.Start, spliceDynamicDataEvent.Data, spliceDynamicDataEvent.DeleteCount, spliceDynamicDataEvent.EncodedLengths); + } + } + } + } +} diff --git a/src/Nethereum.Mud.Contracts/Tables/Store/ResourceIdsTableRecord.cs b/src/Nethereum.Mud.Contracts/Tables/Store/ResourceIdsTableRecord.cs new file mode 100644 index 000000000..9dcdcf779 --- /dev/null +++ b/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 + { + 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; } + } + } +} diff --git a/src/Nethereum.Mud.Contracts/Tables/Store/StoreHooksTableRecord.cs b/src/Nethereum.Mud.Contracts/Tables/Store/StoreHooksTableRecord.cs new file mode 100644 index 000000000..6df70549f --- /dev/null +++ b/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 + { + 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 Hooks { get; set; } + } + } +} + + + + diff --git a/src/Nethereum.Mud.Contracts/Tables/Store/StoreHooksWorldServiceExtensions.cs b/src/Nethereum.Mud.Contracts/Tables/Store/StoreHooksWorldServiceExtensions.cs new file mode 100644 index 000000000..9902e9b19 --- /dev/null +++ b/src/Nethereum.Mud.Contracts/Tables/Store/StoreHooksWorldServiceExtensions.cs @@ -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 GetStoreHooksTableRecord(this WorldService storeService, StoreHooksKey key, BlockParameter blockParameter = null) + { + var table = new StoreHooksTableRecord(); + table.Keys = key; + return await storeService.GetRecordTableQueryAsync(table, blockParameter); + } + + public static async Task SetStoreHooksTableRecordRequestAsync(this WorldService storeService, StoreHooksKey key, List hooks) + { + var table = new StoreHooksTableRecord(); + table.Keys = key; + table.Values = new StoreHooksValue() { Hooks = hooks }; + return await storeService.SetRecordRequestAsync(table); + } + } +} + + diff --git a/src/Nethereum.Mud.Contracts/Tables/Store/TablesTableRecord.cs b/src/Nethereum.Mud.Contracts/Tables/Store/TablesTableRecord.cs new file mode 100644 index 000000000..cd3308292 --- /dev/null +++ b/src/Nethereum.Mud.Contracts/Tables/Store/TablesTableRecord.cs @@ -0,0 +1,73 @@ +using Nethereum.ABI; +using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Mud.EncodingDecoding; +using static Nethereum.Mud.Contracts.Tables.Store.TablesTableRecord; + +namespace Nethereum.Mud.Contracts.Tables.Store +{ + public class TablesTableRecord : TableRecord + { + public TablesTableRecord() : base("store", "Tables") + { + } + + + public class TablesKey + { + [Parameter("bytes32", "tableId", 1)] + public byte[] TableId { get; set; } + + public Resource GetTableIdResource() + { + return ResourceEncoder.Decode(TableId); + } + } + + public class TablesValue + { + [Parameter("bytes32", "fieldLayout", 1)] + public byte[] FieldLayout { get; set; } + [Parameter("bytes32", "keySchema", 2)] + public byte[] KeySchema { get; set; } + [Parameter("bytes32", "valueSchema", 3)] + public byte[] ValueSchema { get; set; } + [Parameter("bytes", "abiEncodedKeyNames", 4)] + public byte[] AbiEncodedKeyNames { get; set; } + [Parameter("bytes", "abiEncodedFieldNames", 5)] + public byte[] AbiEncodedFieldNames { get; set; } + + + public List GetKeyNames() + { + return ABIType.CreateABIType("string[]").Decode>(AbiEncodedKeyNames.Skip(32).ToArray()); + } + + public List GetValueFieldNames() + { + return ABIType.CreateABIType($"string[]").Decode>(AbiEncodedFieldNames.Skip(32).ToArray()); + } + + public List GetValueSchemaFields() + { + var fields = SchemaEncoder.Decode(ValueSchema); + var fieldNames = GetValueFieldNames(); + for (var i = 0; i < fields.Count; i++) + { + fields[i].Name = fieldNames[i]; + } + return fields; + } + + public List GetKeySchemaFields() + { + var fields = SchemaEncoder.Decode(KeySchema, true); + var keyNames = GetKeyNames(); + for (var i = 0; i < fields.Count; i++) + { + fields[i].Name = keyNames[i]; + } + return fields; + } + } + } +} diff --git a/src/Nethereum.Mud.Contracts/Tables/Store/TablesWorldServiceExtensions.cs b/src/Nethereum.Mud.Contracts/Tables/Store/TablesWorldServiceExtensions.cs new file mode 100644 index 000000000..a96e7c4cc --- /dev/null +++ b/src/Nethereum.Mud.Contracts/Tables/Store/TablesWorldServiceExtensions.cs @@ -0,0 +1,19 @@ +using static Nethereum.Mud.Contracts.Tables.Store.TablesTableRecord; +using Nethereum.RPC.Eth.DTOs; +using System.Threading.Tasks; +using Nethereum.Mud.Contracts.World; + +namespace Nethereum.Mud.Contracts.Tables.Store +{ + public static class TablesWorldServiceExtensions + { + public static async Task GetTablesTableRecord(this WorldService storeService, TablesKey key, BlockParameter blockParameter = null) + { + var table = new TablesTableRecord(); + table.Keys = key; + return await storeService.GetRecordTableQueryAsync(table, blockParameter); + } + + } +} + diff --git a/src/Nethereum.Mud.Contracts/Tables/World/BalancesTableRecord.cs b/src/Nethereum.Mud.Contracts/Tables/World/BalancesTableRecord.cs index 08d286c63..362c41226 100644 --- a/src/Nethereum.Mud.Contracts/Tables/World/BalancesTableRecord.cs +++ b/src/Nethereum.Mud.Contracts/Tables/World/BalancesTableRecord.cs @@ -1,4 +1,5 @@ using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Mud.EncodingDecoding; using System.Numerics; using static Nethereum.Mud.Contracts.Tables.World.BalancesTableRecord; @@ -15,6 +16,11 @@ public class BalancesKey { [Parameter("bytes32", "namespaceId", 1)] public byte[] NamespaceId { get; set; } + + public Resource GetNamespaceIdResource() + { + return ResourceEncoder.Decode(NamespaceId); + } } public class BalancesValue diff --git a/src/Nethereum.Mud.Contracts/Tables/World/FunctionSelectorsTableRecord.cs b/src/Nethereum.Mud.Contracts/Tables/World/FunctionSelectorsTableRecord.cs index ba49b161f..2be80b313 100644 --- a/src/Nethereum.Mud.Contracts/Tables/World/FunctionSelectorsTableRecord.cs +++ b/src/Nethereum.Mud.Contracts/Tables/World/FunctionSelectorsTableRecord.cs @@ -1,4 +1,5 @@ using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Mud.EncodingDecoding; using static Nethereum.Mud.Contracts.Tables.World.FunctionSelectorsTableRecord; namespace Nethereum.Mud.Contracts.Tables.World @@ -21,6 +22,11 @@ public class FunctionSelectorsValue public byte[] SystemId { get; set; } [Parameter("bytes4", "systemFunctionSelector", 2)] public byte[] SystemFunctionSelector { get; set; } + + public Resource GetSystemIdResource() + { + return ResourceEncoder.Decode(SystemId); + } } } diff --git a/src/Nethereum.Mud.Contracts/Tables/World/NamespaceDelegationControlTableRecord.cs b/src/Nethereum.Mud.Contracts/Tables/World/NamespaceDelegationControlTableRecord.cs index f76b9b2bd..9465f1009 100644 --- a/src/Nethereum.Mud.Contracts/Tables/World/NamespaceDelegationControlTableRecord.cs +++ b/src/Nethereum.Mud.Contracts/Tables/World/NamespaceDelegationControlTableRecord.cs @@ -1,4 +1,5 @@ using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Mud.EncodingDecoding; using static Nethereum.Mud.Contracts.Tables.World.NamespaceDelegationControlTableRecord; namespace Nethereum.Mud.Contracts.Tables.World @@ -13,6 +14,11 @@ public class NamespaceDelegationControlKey { [Parameter("bytes32", "namespaceId", 1)] public byte[] NamespaceId { get; set; } + + public Resource GetNamespaceIdResource() + { + return ResourceEncoder.Decode(NamespaceId); + } } public class NamespaceDelegationControlValue diff --git a/src/Nethereum.Mud.Contracts/Tables/World/NamespaceOwnerTableRecord.cs b/src/Nethereum.Mud.Contracts/Tables/World/NamespaceOwnerTableRecord.cs index 933bf42bb..c73b5b27d 100644 --- a/src/Nethereum.Mud.Contracts/Tables/World/NamespaceOwnerTableRecord.cs +++ b/src/Nethereum.Mud.Contracts/Tables/World/NamespaceOwnerTableRecord.cs @@ -1,4 +1,5 @@ using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Mud.EncodingDecoding; using static Nethereum.Mud.Contracts.Tables.World.NamespaceOwnerTableRecord; namespace Nethereum.Mud.Contracts.Tables.World @@ -22,7 +23,13 @@ public class NamespaceOwnerKey { [Parameter("bytes32", "namespaceId", 1)] public byte[] NamespaceId { get; set; } + + public Resource GetNamespaceIdResource() + { + return ResourceEncoder.Decode(NamespaceId); + } } + public class NamespaceOwnerValue { diff --git a/src/Nethereum.Mud.Contracts/Tables/World/ResourceAccessTableRecord.cs b/src/Nethereum.Mud.Contracts/Tables/World/ResourceAccessTableRecord.cs index 8af168433..09621e9bb 100644 --- a/src/Nethereum.Mud.Contracts/Tables/World/ResourceAccessTableRecord.cs +++ b/src/Nethereum.Mud.Contracts/Tables/World/ResourceAccessTableRecord.cs @@ -1,5 +1,6 @@ using static Nethereum.Mud.Contracts.Tables.World.ResourceAccessTableRecord; using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Mud.EncodingDecoding; namespace Nethereum.Mud.Contracts.Tables.World { @@ -25,7 +26,13 @@ public class ResourceAccessKey public byte[] ResourceId { get; set; } [Parameter("address", "caller", 2)] public string Caller { get; set; } + + public Resource GetResourceIdResource() + { + return ResourceEncoder.Decode(ResourceId); + } } + public class ResourceAccessValue { diff --git a/src/Nethereum.Mud.Contracts/Tables/World/SystemHooksTableRecord.cs b/src/Nethereum.Mud.Contracts/Tables/World/SystemHooksTableRecord.cs index b6d5b6ce9..d9fe4e078 100644 --- a/src/Nethereum.Mud.Contracts/Tables/World/SystemHooksTableRecord.cs +++ b/src/Nethereum.Mud.Contracts/Tables/World/SystemHooksTableRecord.cs @@ -1,4 +1,5 @@ using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Mud.EncodingDecoding; using static Nethereum.Mud.Contracts.Tables.World.SystemHooksTableRecord; namespace Nethereum.Mud.Contracts.Tables.World @@ -13,7 +14,13 @@ public class SystemHooksKey { [Parameter("bytes32", "systemId", 1)] public byte[] SystemId { get; set; } + + public Resource GetSystemIdResource() + { + return ResourceEncoder.Decode(SystemId); + } } + public class SystemHooksValue { diff --git a/src/Nethereum.Mud.Contracts/Tables/World/SystemRegistryTableRecord.cs b/src/Nethereum.Mud.Contracts/Tables/World/SystemRegistryTableRecord.cs index 57f22e5c3..0aa97cece 100644 --- a/src/Nethereum.Mud.Contracts/Tables/World/SystemRegistryTableRecord.cs +++ b/src/Nethereum.Mud.Contracts/Tables/World/SystemRegistryTableRecord.cs @@ -1,4 +1,5 @@ using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Mud.EncodingDecoding; using static Nethereum.Mud.Contracts.Tables.World.SystemRegistryTableRecord; namespace Nethereum.Mud.Contracts.Tables.World @@ -13,12 +14,18 @@ public class SystemRegistryKey { [Parameter("address", "system", 1)] public string System { get; set; } + } public class SystemRegistryValue { [Parameter("bytes32", "systemId", 1)] public byte[] SystemId { get; set; } + + public Resource GetSystemIdResource() + { + return ResourceEncoder.Decode(SystemId); + } } } diff --git a/src/Nethereum.Mud.Contracts/Tables/World/SystemRegistryWorldServiceExtensions.cs b/src/Nethereum.Mud.Contracts/Tables/World/SystemRegistryWorldServiceExtensions.cs index 3c7ba53e2..a149d659c 100644 --- a/src/Nethereum.Mud.Contracts/Tables/World/SystemRegistryWorldServiceExtensions.cs +++ b/src/Nethereum.Mud.Contracts/Tables/World/SystemRegistryWorldServiceExtensions.cs @@ -1,6 +1,7 @@ using Nethereum.Mud.Contracts.World; using Nethereum.RPC.Eth.DTOs; using static Nethereum.Mud.Contracts.Tables.World.SystemRegistryTableRecord; +using static Nethereum.Mud.Contracts.Tables.World.SystemRegistryTableRecord.SystemRegistryKey; namespace Nethereum.Mud.Contracts.Tables.World diff --git a/src/Nethereum.Mud.Contracts/Tables/World/SystemsTableRecord.cs b/src/Nethereum.Mud.Contracts/Tables/World/SystemsTableRecord.cs index 377bfe559..f5017c394 100644 --- a/src/Nethereum.Mud.Contracts/Tables/World/SystemsTableRecord.cs +++ b/src/Nethereum.Mud.Contracts/Tables/World/SystemsTableRecord.cs @@ -1,4 +1,5 @@ using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Mud.EncodingDecoding; using static Nethereum.Mud.Contracts.Tables.World.SystemsTableRecord; namespace Nethereum.Mud.Contracts.Tables.World @@ -13,6 +14,11 @@ public class SystemsKey { [Parameter("bytes32", "systemId", 1)] public byte[] SystemId { get; set; } + + public Resource GetSystemIdResource() + { + return ResourceEncoder.Decode(SystemId); + } } public class SystemsValue diff --git a/src/Nethereum.Mud.Contracts/World/WorldServiceExtended.cs b/src/Nethereum.Mud.Contracts/World/WorldServiceExtended.cs index 46e7d6b79..f784e4ed8 100644 --- a/src/Nethereum.Mud.Contracts/World/WorldServiceExtended.cs +++ b/src/Nethereum.Mud.Contracts/World/WorldServiceExtended.cs @@ -7,6 +7,7 @@ using Nethereum.Contracts.ContractHandlers; using Nethereum.RPC.Eth.DTOs; using Org.BouncyCastle.Crypto.Tls; +using Nethereum.Mud.EncodingDecoding; namespace Nethereum.Mud.Contracts.World { diff --git a/src/Nethereum.Mud/EncodedTableRecord.cs b/src/Nethereum.Mud/EncodedTableRecord.cs new file mode 100644 index 000000000..8e0c67eb8 --- /dev/null +++ b/src/Nethereum.Mud/EncodedTableRecord.cs @@ -0,0 +1,12 @@ +using Nethereum.Mud.EncodingDecoding; + +namespace Nethereum.Mud +{ + public class EncodedTableRecord + { + public byte[] TableId { get; set; } + + public List Key { get; set; } + public EncodedValues EncodedValues { get; set; } + } +} diff --git a/src/Nethereum.Mud/EncodedLengths.cs b/src/Nethereum.Mud/EncodingDecoding/EncodedLengths.cs similarity index 75% rename from src/Nethereum.Mud/EncodedLengths.cs rename to src/Nethereum.Mud/EncodingDecoding/EncodedLengths.cs index a51e5de7e..9da959389 100644 --- a/src/Nethereum.Mud/EncodedLengths.cs +++ b/src/Nethereum.Mud/EncodingDecoding/EncodedLengths.cs @@ -1,4 +1,4 @@ -namespace Nethereum.Mud +namespace Nethereum.Mud.EncodingDecoding { public class EncodedLengths { diff --git a/src/Nethereum.Mud/EncodedLengthsEncoderDecoder.cs b/src/Nethereum.Mud/EncodingDecoding/EncodedLengthsEncoderDecoder.cs similarity index 81% rename from src/Nethereum.Mud/EncodedLengthsEncoderDecoder.cs rename to src/Nethereum.Mud/EncodingDecoding/EncodedLengthsEncoderDecoder.cs index a1703d930..8ea332fb3 100644 --- a/src/Nethereum.Mud/EncodedLengthsEncoderDecoder.cs +++ b/src/Nethereum.Mud/EncodingDecoding/EncodedLengthsEncoderDecoder.cs @@ -2,25 +2,25 @@ using Nethereum.Util; -namespace Nethereum.Mud +namespace Nethereum.Mud.EncodingDecoding { public class EncodedLengthsEncoderDecoder { public static EncodedLengths Decode(byte[] encodedLenghtsBytes) { var byteLenghtData = encodedLenghtsBytes.Skip(32 - 7).Take(7).ToArray(); - var totalLength = ABIType.CreateABIType("uint56").DecodePacked(byteLenghtData); + var totalLength = ABIType.CreateABIType("uint56").DecodePacked(byteLenghtData); - var sizes = (List)((ArrayType)ABIType.CreateABIType("uint40[]")).DecodePackedUsingElementPacked(encodedLenghtsBytes.Take(32-7).ToArray(), typeof(List)); + var sizes = (List)((ArrayType)ABIType.CreateABIType("uint40[]")).DecodePackedUsingElementPacked(encodedLenghtsBytes.Take(32 - 7).ToArray(), typeof(List)); sizes.Reverse(); - return new EncodedLengths() { TotalLength = totalLength, Lengths = sizes.ToArray()}; + return new EncodedLengths() { TotalLength = totalLength, Lengths = sizes.ToArray() }; } public static byte[] Encode(byte[][] dynamicFields) { var totalLengthBytes = ABIType.CreateABIType("uint56").EncodePacked(dynamicFields.Sum(x => x.Length)); var sizesBytes = ((ArrayType)ABIType.CreateABIType("uint40[]")).EncodePackedUsingElementPacked(dynamicFields.Reverse().Select(x => x.Length).ToArray()); - + return sizesBytes.Concat(totalLengthBytes).ToArray().PadBytesLeft(32); } } diff --git a/src/Nethereum.Mud/EncodedValues.cs b/src/Nethereum.Mud/EncodingDecoding/EncodedValues.cs similarity index 81% rename from src/Nethereum.Mud/EncodedValues.cs rename to src/Nethereum.Mud/EncodingDecoding/EncodedValues.cs index 6e04e1f48..199ae572d 100644 --- a/src/Nethereum.Mud/EncodedValues.cs +++ b/src/Nethereum.Mud/EncodingDecoding/EncodedValues.cs @@ -1,4 +1,4 @@ -namespace Nethereum.Mud +namespace Nethereum.Mud.EncodingDecoding { public class EncodedValues { diff --git a/src/Nethereum.Mud/FieldLayoutEncoder.cs b/src/Nethereum.Mud/EncodingDecoding/FieldLayoutEncoder.cs similarity index 95% rename from src/Nethereum.Mud/FieldLayoutEncoder.cs rename to src/Nethereum.Mud/EncodingDecoding/FieldLayoutEncoder.cs index 560103b3f..041fd5b06 100644 --- a/src/Nethereum.Mud/FieldLayoutEncoder.cs +++ b/src/Nethereum.Mud/EncodingDecoding/FieldLayoutEncoder.cs @@ -1,7 +1,7 @@ using Nethereum.RLP; using Nethereum.Util; -namespace Nethereum.Mud +namespace Nethereum.Mud.EncodingDecoding { public static class FieldLayoutEncoder { diff --git a/src/Nethereum.Mud/KeyEncoderDecoder.cs b/src/Nethereum.Mud/EncodingDecoding/KeyEncoderDecoder.cs similarity index 96% rename from src/Nethereum.Mud/KeyEncoderDecoder.cs rename to src/Nethereum.Mud/EncodingDecoding/KeyEncoderDecoder.cs index e5e736bf4..2a882d6d3 100644 --- a/src/Nethereum.Mud/KeyEncoderDecoder.cs +++ b/src/Nethereum.Mud/EncodingDecoding/KeyEncoderDecoder.cs @@ -7,14 +7,14 @@ using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Mud.Exceptions; -namespace Nethereum.Mud +namespace Nethereum.Mud.EncodingDecoding { public class KeyEncoderDecoder { public static List EncodeKey(T key) { - if(key == null) return new List(); - var parametersEncoder = new ABI.FunctionEncoding.ParametersEncoder(); + if (key == null) return new List(); + var parametersEncoder = new ParametersEncoder(); var keys = parametersEncoder.GetParameterAttributeValues(typeof(T), key); keys = keys.OrderBy(x => x.ParameterAttribute.Order).ToList(); var fieldValues = new List(); @@ -114,7 +114,7 @@ public static List DecodeKey(List outputBytes, params P var fieldSize = abiType.FixedSize; var bytes = outputBytes[currentIndex]; var value = abiType.Decode(bytes, field.Parameter.DecodedType); - currentIndex ++; + currentIndex++; field.Result = value; } return outputParameters.ToList(); @@ -155,7 +155,7 @@ public static List DecodeKeyToFieldValues(List outputBytes, public static List DecodeKey(byte[] outputBytes, List fields) { - return DecodeKeyToFieldValues(outputBytes, fields).Select(f => f.Value).ToList(); + return DecodeKeyToFieldValues(outputBytes, fields).Select(f => f.Value).ToList(); } public static List DecodeKey(List outputBytes, List fields) diff --git a/src/Nethereum.Mud/ResourceEncoder.cs b/src/Nethereum.Mud/EncodingDecoding/ResourceEncoder.cs similarity index 94% rename from src/Nethereum.Mud/ResourceEncoder.cs rename to src/Nethereum.Mud/EncodingDecoding/ResourceEncoder.cs index bfb9eae8c..23571760d 100644 --- a/src/Nethereum.Mud/ResourceEncoder.cs +++ b/src/Nethereum.Mud/EncodingDecoding/ResourceEncoder.cs @@ -1,6 +1,6 @@ using System.Text; -namespace Nethereum.Mud +namespace Nethereum.Mud.EncodingDecoding { public static class ResourceEncoder { @@ -15,7 +15,7 @@ public static Resource Decode(byte[] resourceBytes) Array.Copy(resourceBytes, 16, nameBytes, 0, 16); resource.Namespace = Encoding.UTF8.GetString(namespaceBytes).TrimEnd('\0'); resource.Name = Encoding.UTF8.GetString(nameBytes).TrimEnd('\0'); - resource.ResourceId = resourceId; + resource.ResourceId = resourceId; return resource; } @@ -41,24 +41,24 @@ public static byte[] EncodeOffchainTable(string @namespace, string name) public static byte[] EncodeRootOffchainTable(string name) { - return Encode(Resource.RESOURCE_OFFCHAIN_TABLE, String.Empty, name); + return Encode(Resource.RESOURCE_OFFCHAIN_TABLE, string.Empty, name); } public static byte[] EncodeSystem(string @namespace, string name) { return Encode(Resource.RESOURCE_SYSTEM, @namespace, name); } - + public static byte[] EncodeRootSystem(string name) { return Encode(Resource.RESOURCE_SYSTEM, string.Empty, name); } - - + + public static byte[] Encode(byte[] typeId, string @namespace, string name = "") { - + // Check for typeId length to ensure it's exactly 2 bytes. if (typeId.Length != 2) throw new ArgumentException("Type ID must be exactly 2 bytes.", nameof(typeId)); @@ -66,7 +66,7 @@ public static byte[] Encode(byte[] typeId, string @namespace, string name = "") if (typeId[0] == Resource.RESOURCE_NAMESPACE[0] && typeId[1] == Resource.RESOURCE_NAMESPACE[1] && !string.IsNullOrEmpty(name)) throw new ArgumentException("Name must not be provided for a namespace.", nameof(name)); - if (@namespace.Length > 14) throw new ArgumentException("Namespace must be 14 bytes or fewer.", nameof(@namespace)); + if (@namespace.Length > 14) throw new ArgumentException("Namespace must be 14 bytes or fewer.", nameof(@namespace)); // Ensure the name is correctly sized (30 bytes max). if (name.Length > 16) throw new ArgumentException("Name must be 16 bytes or fewer.", nameof(name)); diff --git a/src/Nethereum.Mud/SchemaEncoder.cs b/src/Nethereum.Mud/EncodingDecoding/SchemaEncoder.cs similarity index 98% rename from src/Nethereum.Mud/SchemaEncoder.cs rename to src/Nethereum.Mud/EncodingDecoding/SchemaEncoder.cs index faea8eaef..8c3a37851 100644 --- a/src/Nethereum.Mud/SchemaEncoder.cs +++ b/src/Nethereum.Mud/EncodingDecoding/SchemaEncoder.cs @@ -3,11 +3,11 @@ using Nethereum.Mud.Exceptions; using Nethereum.RLP; -namespace Nethereum.Mud +namespace Nethereum.Mud.EncodingDecoding { public static class SchemaEncoder - { + { public const int MAX_NUMBER_OF_FIELDS = 28; public const int MAX_NUMBER_OF_DYNAMIC_FIELDS = 5; @@ -19,7 +19,7 @@ public static ABIType GetABIType(int index) //need to validate if it is the same if not use index position 92? public static bool IsDynamic(int index) { - return GetABIType(index).IsDynamic(); + return GetABIType(index).IsDynamic(); } public static bool IsStatic(int index) @@ -45,7 +45,7 @@ public static List Decode(byte[] schema, bool isKeySchema = false) startIndex += numStaticFields; for (var i = 0; i < numDynamicFields; i++) { - fieldCount = i + 1; + fieldCount = fieldCount + 1; var abiType = SchemaAbiTypes[schema[i + startIndex]]; fieldInfos.Add(new FieldInfo(abiType, isKeySchema, null, fieldCount)); } @@ -108,7 +108,7 @@ public static byte[] EncodeTypesToByteArray(params string[] schemaTypes) public static string EncodeTypesToHex(params string[] schemaTypes) { - return EncodeTypesToByteArray(schemaTypes).ToHex(); + return EncodeTypesToByteArray(schemaTypes).ToHex(); } diff --git a/src/Nethereum.Mud/ValueEncoderDecoder.cs b/src/Nethereum.Mud/EncodingDecoding/ValueEncoderDecoder.cs similarity index 91% rename from src/Nethereum.Mud/ValueEncoderDecoder.cs rename to src/Nethereum.Mud/EncodingDecoding/ValueEncoderDecoder.cs index 30d75eb6a..82bdc4c0e 100644 --- a/src/Nethereum.Mud/ValueEncoderDecoder.cs +++ b/src/Nethereum.Mud/EncodingDecoding/ValueEncoderDecoder.cs @@ -6,7 +6,7 @@ using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Mud.Exceptions; -namespace Nethereum.Mud +namespace Nethereum.Mud.EncodingDecoding { public class ValueEncoderDecoder @@ -27,7 +27,7 @@ public static byte[] EncodeField(FieldValue fieldValue) public static byte[] EncodeValuesAsyByteArray(T value) { - var parametersEncoder = new ABI.FunctionEncoding.ParametersEncoder(); + var parametersEncoder = new ParametersEncoder(); var values = parametersEncoder.GetParameterAttributeValues(typeof(T), value); values = values.OrderBy(x => x.ParameterAttribute.Order).ToList(); var fieldValues = new List(); @@ -46,7 +46,7 @@ public static byte[] EncodeValuesAsyByteArray(List values) public static EncodedValues EncodedValues(T value) { - var parametersEncoder = new ABI.FunctionEncoding.ParametersEncoder(); + var parametersEncoder = new ParametersEncoder(); var values = parametersEncoder.GetParameterAttributeValues(typeof(T), value); values = values.OrderBy(x => x.ParameterAttribute.Order).ToList(); var fieldValues = new List(); @@ -68,7 +68,7 @@ public static EncodedValues EncodeValues(List fieldValues) throw new SchemaInvalidNumberOfFieldsException(); } - if ((valueFields.Length + dynamicFields.Length) > SchemaEncoder.MAX_NUMBER_OF_FIELDS) + if (valueFields.Length + dynamicFields.Length > SchemaEncoder.MAX_NUMBER_OF_FIELDS) { throw new SchemaInvalidNumberOfFieldsException(); } @@ -82,7 +82,7 @@ public static EncodedValues EncodeValues(List fieldValues) EncodedLengths = encodedLengths, DynamicData = ByteUtil.Merge(dynamicFieldsBytes) }; - + } public static List DecodeValues(byte[] outputBytes, List fields) @@ -97,7 +97,7 @@ public static T DecodeValues(string outputBytes) where T : new() public static T DecodeValues(byte[] staticData, byte[] encodedLengths, byte[] dynamicData) where T : new() { - return DecodeValues(new EncodedValues { StaticData = staticData, EncodedLengths = encodedLengths, DynamicData = dynamicData }); + return DecodeValues(new EncodedValues { StaticData = staticData, EncodedLengths = encodedLengths, DynamicData = dynamicData }); } public static T DecodeValues(byte[] outputBytes) where T : new() @@ -144,7 +144,7 @@ public static List DecodeValues(byte[] outputBytes, params Para var currentIndex = 0; foreach (var field in staticFields) - { + { var abiType = field.Parameter.ABIType; var fieldSize = abiType.StaticSize; var bytes = outputBytes.Skip(currentIndex).Take(abiType.StaticSize).ToArray(); @@ -170,7 +170,7 @@ public static List DecodeValues(byte[] outputBytes, params Para if (dynamicFields[i].Parameter.ABIType is ArrayType arrayAbiType) { - + value = arrayAbiType.DecodePackedUsingElementPacked(bytes, dynamicFields[i].Parameter.DecodedType); } @@ -205,12 +205,12 @@ public static List DecodeValuesToFieldValues(byte[] outputBytes, Lis var dynamicFields = fields.Where(f => f.ABIType.IsDynamic() == true && f.IsKey == false).OrderBy(f => f.Order).ToArray(); var encodedLengths = EncodedLengthsEncoderDecoder.Decode(outputBytes.Skip(currentIndex).ToArray()); currentIndex += 32; - for(int i = 0; i < dynamicFields.Length; i++) + for (int i = 0; i < dynamicFields.Length; i++) { var fieldSize = encodedLengths.Lengths[i]; var bytes = outputBytes.Skip(currentIndex).Take(fieldSize).ToArray(); object value; - if(bytes.Length == 0) + if (bytes.Length == 0) { //check what direction is the padding or just empty bytes = bytes.PadBytes(fieldSize); @@ -218,19 +218,19 @@ public static List DecodeValuesToFieldValues(byte[] outputBytes, Lis if (dynamicFields[i].ABIType is ArrayType arrayAbiType) { - value = arrayAbiType.DecodePackedUsingElementPacked(bytes, arrayAbiType.GetDefaultDecodingType()); - + value = arrayAbiType.DecodePackedUsingElementPacked(bytes, arrayAbiType.GetDefaultDecodingType()); + } else { - value = dynamicFields[i].ABIType.DecodePacked(bytes, dynamicFields[i].ABIType.GetDefaultDecodingType()); - + value = dynamicFields[i].ABIType.DecodePacked(bytes, dynamicFields[i].ABIType.GetDefaultDecodingType()); + } fieldValues.Add(new FieldValue(dynamicFields[i].Type, value, dynamicFields[i].Name, dynamicFields[i].Order)); currentIndex += fieldSize; } - + return fieldValues; } diff --git a/src/Nethereum.Mud/Exceptions/SchemaInvalidNumberOfFieldsException.cs b/src/Nethereum.Mud/Exceptions/SchemaInvalidNumberOfFieldsException.cs index 487cad983..0dd42d10f 100644 --- a/src/Nethereum.Mud/Exceptions/SchemaInvalidNumberOfFieldsException.cs +++ b/src/Nethereum.Mud/Exceptions/SchemaInvalidNumberOfFieldsException.cs @@ -1,4 +1,6 @@ -namespace Nethereum.Mud.Exceptions +using Nethereum.Mud.EncodingDecoding; + +namespace Nethereum.Mud.Exceptions { public class SchemaInvalidNumberOfFieldsException : Exception { diff --git a/src/Nethereum.Mud/FieldInfo.cs b/src/Nethereum.Mud/FieldInfo.cs index e35309858..316944b6e 100644 --- a/src/Nethereum.Mud/FieldInfo.cs +++ b/src/Nethereum.Mud/FieldInfo.cs @@ -5,7 +5,7 @@ namespace Nethereum.Mud { public class FieldInfo { - public string Name { get; private set; } + public string Name { get; set; } public string Type { get; private set; } public ABIType ABIType { get; private set; } public int Order { get; private set; } diff --git a/src/Nethereum.Mud/FieldValue.cs b/src/Nethereum.Mud/FieldValue.cs index dbbe5cd0f..68cc0e08e 100644 --- a/src/Nethereum.Mud/FieldValue.cs +++ b/src/Nethereum.Mud/FieldValue.cs @@ -4,6 +4,7 @@ using Nethereum.ABI.FunctionEncoding.Attributes; using Nethereum.ABI.FunctionEncoding; using Nethereum.ABI; +using Nethereum.Mud.EncodingDecoding; namespace Nethereum.Mud { @@ -33,24 +34,4 @@ public FieldValue(string type, object value, bool isKey, string name = null, int } } - - public class Schema - { - public int TotalLength { get; set; } - public int NumberDynamicFields { get; set; } - public int NumberStaticFields { get; set; } - public byte[] SchemaBytes { get; set; } - - public string[] GetSchemaTypes() - { - var totalNumberOfFields = SchemaBytes[2] + SchemaBytes[3]; - var schemaTypes = new string[totalNumberOfFields]; - for (var i = 0; i < totalNumberOfFields; i++) - { - var index = SchemaBytes[i + 4]; - schemaTypes[i] = SchemaEncoder.SchemaAbiTypes[index]; - } - return schemaTypes; - } - } } diff --git a/src/Nethereum.Mud/ITableRecord.cs b/src/Nethereum.Mud/ITableRecord.cs new file mode 100644 index 000000000..cfc0be7f0 --- /dev/null +++ b/src/Nethereum.Mud/ITableRecord.cs @@ -0,0 +1,8 @@ +namespace Nethereum.Mud +{ + public interface ITableRecord: ITableRecordSingleton + { + void DecodeKey(List encodedKey); + List GetEncodedKey(); + } +} diff --git a/src/Nethereum.Mud/ITableRecordSingleton.cs b/src/Nethereum.Mud/ITableRecordSingleton.cs new file mode 100644 index 000000000..c46774e0e --- /dev/null +++ b/src/Nethereum.Mud/ITableRecordSingleton.cs @@ -0,0 +1,17 @@ +using Nethereum.Mud.EncodingDecoding; + +namespace Nethereum.Mud +{ + public interface ITableRecordSingleton + { + byte[] ResourceId { get; } + string Namespace { get; } + string TableName { get; } + + void DecodeValues(byte[] staticData, byte[] encodedLengths, byte[] dynamicData); + EncodedValues GetEncodeValues(); + void DecodeValues(EncodedValues encodedValues); + void DecodeValues(byte[] encodedValues); + + } +} diff --git a/src/Nethereum.Mud/TableRecord.cs b/src/Nethereum.Mud/TableRecord.cs index af431bea6..5535bbfcb 100644 --- a/src/Nethereum.Mud/TableRecord.cs +++ b/src/Nethereum.Mud/TableRecord.cs @@ -1,17 +1,19 @@ -namespace Nethereum.Mud +using Nethereum.Mud.EncodingDecoding; + +namespace Nethereum.Mud { - public abstract class TableRecord: TableRecordSingleton where TValue : class, new() where TKey : class, new() + public abstract class TableRecord : TableRecordSingleton, ITableRecord where TValue : class, new() where TKey : class, new() { - public TableRecord(string nameSpace, string tableName):base(nameSpace, tableName) + public TableRecord(string nameSpace, string tableName) : base(nameSpace, tableName) { - Keys = new TKey(); + Keys = new TKey(); } - public TableRecord (string tableName):base(tableName) + public TableRecord(string tableName) : base(tableName) { Keys = new TKey(); } - + public TKey Keys { get; set; } public virtual List GetEncodedKey() @@ -19,6 +21,11 @@ public virtual List GetEncodedKey() return KeyEncoderDecoder.EncodeKey(Keys); } + public virtual void DecodeKey(List encodedKey) + { + Keys = KeyEncoderDecoder.DecodeKey(encodedKey); + } + } } diff --git a/src/Nethereum.Mud/TableRecordSingleton.cs b/src/Nethereum.Mud/TableRecordSingleton.cs index 05bd047f5..9821b6183 100644 --- a/src/Nethereum.Mud/TableRecordSingleton.cs +++ b/src/Nethereum.Mud/TableRecordSingleton.cs @@ -1,14 +1,16 @@ -namespace Nethereum.Mud +using Nethereum.Mud.EncodingDecoding; + +namespace Nethereum.Mud { - public abstract class TableRecordSingleton where TValue : class, new() + + public abstract class TableRecordSingleton: ITableRecordSingleton where TValue : class, new() { - public static byte[] TableResourceId { get; protected set; } public TableRecordSingleton(string nameSpace, string tableName) { Namespace = nameSpace; TableName = tableName; Values = new TValue(); - TableResourceId = ResourceId; + } public TableRecordSingleton(string name) @@ -16,7 +18,7 @@ public TableRecordSingleton(string name) Namespace = String.Empty; TableName = name; Values = new TValue(); - TableResourceId = ResourceId; + } public string Namespace { get; protected set; } public string TableName { get; protected set; } diff --git a/src/Nethereum.Mud/TableRepository/ITableRepository.cs b/src/Nethereum.Mud/TableRepository/ITableRepository.cs new file mode 100644 index 000000000..b7a841d02 --- /dev/null +++ b/src/Nethereum.Mud/TableRepository/ITableRepository.cs @@ -0,0 +1,24 @@ +using Nethereum.Mud.EncodingDecoding; + +namespace Nethereum.Mud.TableRepository +{ + public interface ITableRepository + { + Task DeleteRecordAsync(byte[] tableId, List key); + Task DeleteRecordAsync(string tableIdHex, string keyHex); + Task DeleteTableAsync(string tableIdHex); + Task GetRecordAsync(byte[] tableId, byte[] key); + Task GetRecordAsync(string tableIdHex, string keyHex); + Task> GetRecordsAsync(byte[] tableId); + Task> GetRecordsAsync(string tableIdHex); + Task> GetTableRecordsAsync(string tableIdHex) where TTableRecord : ITableRecordSingleton, new(); + Task SetRecordAsync(byte[] tableId, byte[] key, EncodedValues encodedValues); + Task SetRecordAsync(byte[] tableId, List key, byte[] staticData, byte[] encodedLengths, byte[] dynamicData); + Task SetRecordAsync(string tableIdHex, string keyHex, byte[] staticData, byte[] encodedLengths, byte[] dynamicData); + Task SetRecordAsync(string tableIdHex, string keyHex, EncodedValues encodedValues); + Task SetSpliceDynamicDataAsync(byte[] tableId, List key, ulong start, byte[] newData, ulong deleteCount, byte[] encodedLengths); + Task SetSpliceDynamicDataAsync(string tableIdHex, string keyHex, ulong start, byte[] newData, ulong deleteCount, byte[] encodedLengths); + Task SetSpliceStaticDataAsync(byte[] tableId, List key, ulong start, byte[] newData); + Task SetSpliceStaticDataAsync(string tableIdHex, string keyHex, ulong start, byte[] newData); + } +} \ No newline at end of file diff --git a/src/Nethereum.Mud/TableRepository/InMemoryTableRepository.cs b/src/Nethereum.Mud/TableRepository/InMemoryTableRepository.cs new file mode 100644 index 000000000..2bb479741 --- /dev/null +++ b/src/Nethereum.Mud/TableRepository/InMemoryTableRepository.cs @@ -0,0 +1,236 @@ +using Nethereum.Hex.HexConvertors.Extensions; +using Nethereum.Mud.EncodingDecoding; + + +namespace Nethereum.Mud.TableRepository +{ + public class InMemoryTableRepository : ITableRepository + { + public Dictionary> Tables { get; set; } + + public InMemoryTableRepository() + { + Tables = new Dictionary>(); + } + + public Task GetRecordAsync(byte[] tableId, byte[] key) + { + return GetRecordAsync(tableId.ToHex(true), key.ToHex(true)); + } + + public Task GetRecordAsync(string tableIdHex, string keyHex) + { + tableIdHex = tableIdHex.EnsureHexPrefix(); + keyHex = keyHex.EnsureHexPrefix(); + + if (Tables.ContainsKey(tableIdHex)) + { + if (Tables[tableIdHex].ContainsKey(keyHex)) + { + return Task.FromResult(Tables[tableIdHex][keyHex]); + } + } + return Task.FromResult(null); + } + + public Task> GetRecordsAsync(byte[] tableId) + { + return GetRecordsAsync(tableId.ToHex(true)); + } + + public Task> GetRecordsAsync(string tableIdHex) + { + tableIdHex = tableIdHex.EnsureHexPrefix(); + var records = new List(); + if (Tables.ContainsKey(tableIdHex)) + { + foreach (var key in Tables[tableIdHex].Keys) + { + records.Add(new EncodedTableRecord() + { + TableId = tableIdHex.HexToByteArray(), + Key = ConvertCommaSeparatedHexToKey(key), + EncodedValues = Tables[tableIdHex][key] + }); + } + + } + + return Task.FromResult>(records); + + } + + public async Task> GetTableRecordsAsync(byte[] tableId) where TTableRecord : ITableRecordSingleton, new() + { + return await GetTableRecordsAsync(tableId.ToHex(true)); + } + + public async Task> GetTableRecordsAsync(string tableIdHex) where TTableRecord : ITableRecordSingleton, new() + { + tableIdHex.EnsureHexPrefix(); + var records = await GetRecordsAsync(tableIdHex); + var result = new List(); + foreach (var record in records) + { + var tableRecord = new TTableRecord(); + tableRecord.DecodeValues(record.EncodedValues); + + if (tableRecord is ITableRecord tableRecordKey) + { + tableRecordKey.DecodeKey(record.Key); + } + + result.Add(tableRecord); + } + return result; + } + + + + public Task SetRecordAsync(byte[] tableId, byte[] key, EncodedValues encodedValues) + { + return SetRecordAsync(tableId.ToHex(true), key.ToHex(true), encodedValues); + } + + public Task SetRecordAsync(string tableIdHex, string keyHex, EncodedValues encodedValues) + { + tableIdHex = tableIdHex.EnsureHexPrefix(); + keyHex = keyHex.EnsureHexPrefix(); + if (!Tables.ContainsKey(tableIdHex)) + { + Tables[tableIdHex] = new Dictionary(); + } + Tables[tableIdHex][keyHex] = encodedValues; + return Task.CompletedTask; + } + + public static string ConvertKeyToCommaSeparatedHex(List key) + { + return string.Join(",", key.Select(k => k.ToHex(true))); + } + + public static List ConvertCommaSeparatedHexToKey(string key) + { + return key.Split(',').Select(k => k.HexToByteArray()).ToList(); + } + + + public Task SetRecordAsync(byte[] tableId, List key, byte[] staticData, byte[] encodedLengths, byte[] dynamicData) + { + return SetRecordAsync(tableId.ToHex(true), ConvertKeyToCommaSeparatedHex(key), staticData, encodedLengths, dynamicData); + } + + public Task SetRecordAsync(string tableIdHex, string keyHex, byte[] staticData, byte[] encodedLengths, byte[] dynamicData) + { + tableIdHex = tableIdHex.EnsureHexPrefix(); + keyHex = keyHex.EnsureHexPrefix(); + + if (!Tables.ContainsKey(tableIdHex)) + { + Tables[tableIdHex] = new Dictionary(); + } + Tables[tableIdHex][keyHex] = new EncodedValues() + { + StaticData = staticData, + EncodedLengths = encodedLengths, + DynamicData = dynamicData + }; + + return Task.CompletedTask; + } + + public byte[] SpliceBytes(byte[] data, int start, int deleteCount, byte[] newData) + { + var dataNibbles = data.ToList(); + var newDataNibbles = newData; + if (start + deleteCount > dataNibbles.Count) + { + for (var i = dataNibbles.Count; i < start + deleteCount; i++) + { + dataNibbles.Add(0); + } + } + dataNibbles.RemoveRange(start, deleteCount); + return dataNibbles.Concat(newDataNibbles).ToArray(); + } + + public Task SetSpliceStaticDataAsync(byte[] tableId, List key, ulong start, byte[] newData) + { + return SetSpliceStaticDataAsync(tableId.ToHex(true), ConvertKeyToCommaSeparatedHex(key), start, newData); + } + + public async Task SetSpliceStaticDataAsync(string tableIdHex, string keyHex, ulong start, byte[] newData) + { + tableIdHex = tableIdHex.EnsureHexPrefix(); + keyHex = keyHex.EnsureHexPrefix(); + + var record = await GetRecordAsync(tableIdHex, keyHex); + if (record == null) + { + record = new EncodedValues(); + record.EncodedLengths = new byte[0]; + record.DynamicData = new byte[0]; + record.StaticData = new byte[0]; + } + + record.StaticData = SpliceBytes(record.StaticData, (int)start, newData.Length, newData); + await SetRecordAsync(tableIdHex, keyHex, record); + } + + public Task SetSpliceDynamicDataAsync(byte[] tableId, List key, ulong start, byte[] newData, ulong deleteCount, byte[] encodedLengths) + { + return SetSpliceDynamicDataAsync(tableId.ToHex(true), ConvertKeyToCommaSeparatedHex(key), start, newData, deleteCount, encodedLengths); + } + + public async Task SetSpliceDynamicDataAsync(string tableIdHex, string keyHex, ulong start, byte[] newData, ulong deleteCount, byte[] encodedLengths) + { + tableIdHex = tableIdHex.EnsureHexPrefix(); + keyHex = keyHex.EnsureHexPrefix(); + + var record = await GetRecordAsync(tableIdHex, keyHex); + if (record == null) + { + record = new EncodedValues(); + record.EncodedLengths = new byte[0]; + record.DynamicData = new byte[0]; + record.StaticData = new byte[0]; + } + record.EncodedLengths = encodedLengths; + record.DynamicData = SpliceBytes(record.DynamicData, (int)start, (int)deleteCount, newData); + await SetRecordAsync(tableIdHex, keyHex, record); + } + + public Task DeleteRecordAsync(byte[] tableId, List key) + { + return DeleteRecordAsync(tableId.ToHex(true), ConvertKeyToCommaSeparatedHex(key)); + } + + public Task DeleteRecordAsync(string tableIdHex, string keyHex) + { + tableIdHex = tableIdHex.EnsureHexPrefix(); + keyHex = keyHex.EnsureHexPrefix(); + + if (Tables.ContainsKey(tableIdHex)) + { + if (Tables[tableIdHex].ContainsKey(keyHex)) + { + Tables[tableIdHex].Remove(keyHex); + } + } + return Task.CompletedTask; + } + + public Task DeleteTableAsync(string tableIdHex) + { + tableIdHex = tableIdHex.EnsureHexPrefix(); + + + if (Tables.ContainsKey(tableIdHex)) + { + Tables.Remove(tableIdHex); + } + return Task.CompletedTask; + } + + } +} diff --git a/src/Nethereum.Mud/TableTypeRegistry.cs b/src/Nethereum.Mud/TableTypeRegistry.cs new file mode 100644 index 000000000..3564afb17 --- /dev/null +++ b/src/Nethereum.Mud/TableTypeRegistry.cs @@ -0,0 +1,41 @@ +namespace Nethereum.Mud +{ + public class TableTypeRegistry + { + public static Dictionary TableTypes = new Dictionary(); + + public static void RegisterTableType(string tableIdHex, Type tableType) + { + TableTypes[tableIdHex] = tableType; + } + + public static Type GetTableType(string tableIdHex) + { + return TableTypes[tableIdHex]; + } + } + + public class TableIdRegistry + { + public static Dictionary TableIds = new Dictionary(); + + public static void RegisterTableId() where TTable : ITableRecordSingleton, new() + { + if (!TableIds.ContainsKey(typeof(TTable))) + { + TableIds[typeof(TTable)] = new TTable().ResourceId; + } + } + + public static byte[] GetTableId() where TTable : ITableRecordSingleton, new() + { + if(!TableIds.ContainsKey(typeof(TTable))) + { + TableIds[typeof(TTable)] = new TTable().ResourceId; + } + + return TableIds[typeof(TTable)]; + } + + } +} diff --git a/tests/Nethereum.Mud.IntegrationTests/WorldServiceTests.cs b/tests/Nethereum.Mud.IntegrationTests/WorldServiceTests.cs index 9e7e639ec..ae55d641c 100644 --- a/tests/Nethereum.Mud.IntegrationTests/WorldServiceTests.cs +++ b/tests/Nethereum.Mud.IntegrationTests/WorldServiceTests.cs @@ -14,6 +14,11 @@ using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Mud.Contracts.Tables.World; using static Nethereum.Mud.Contracts.Tables.World.ResourceAccessTableRecord; +using Nethereum.Web3; +using Nethereum.Mud.Contracts.StoreEvents; +using Nethereum.Mud.TableRepository; +using Nethereum.Mud.EncodingDecoding; +using Nethereum.Mud.Contracts.Tables.Store; namespace Nethereum.Mud.IntegrationTests { @@ -57,6 +62,11 @@ public WorldService GetWorldService() return new WorldService(web3, WorldAddress); } + public IWeb3 GetWeb3() + { + return new Nethereum.Web3.Web3(new Nethereum.Web3.Accounts.Account(OwnerPK), WorldUrl); + } + public WorldService GetUserWorldService() { var web3 = new Nethereum.Web3.Web3(new Nethereum.Web3.Accounts.Account(UserPK), WorldUrl); @@ -81,11 +91,11 @@ public class IncrementFunction : FunctionMessage public void ShouldGenerateResourceIdsOnDifferentAbstractImplementations() { var counterTableResourceId = new CounterTable().ResourceId; - var counterTableResourceId2 = CounterTable.TableResourceId; + var counterTableResourceId2 = TableIdRegistry.GetTableId(); Assert.Equal(counterTableResourceId.ToHex(), counterTableResourceId2.ToHex()); var itemTableResourceId = new ItemTable().ResourceId; - var itemTableResourceId2 = ItemTable.TableResourceId; + var itemTableResourceId2 = TableIdRegistry.GetTableId(); Assert.Equal(itemTableResourceId.ToHex(), itemTableResourceId2.ToHex()); Assert.NotEqual(counterTableResourceId.ToHex(), itemTableResourceId.ToHex()); @@ -139,30 +149,30 @@ public async Task ShouldSetAndGetAccessTable() //using the access management system //first owner account var accessSystem = new AccessManagementSystemService(worldService.Web3, worldService.ContractAddress); - var receipt2 = await accessSystem.GrantAccessRequestAndWaitForReceiptAsync(CounterTable.TableResourceId, worldService.Web3.TransactionManager.Account.Address); + var receipt2 = await accessSystem.GrantAccessRequestAndWaitForReceiptAsync(TableIdRegistry.GetTableId(), worldService.Web3.TransactionManager.Account.Address); var resourceAccessTable = new ResourceAccessTableRecord(); - resourceAccessTable.Keys.ResourceId = CounterTable.TableResourceId; + resourceAccessTable.Keys.ResourceId = TableIdRegistry.GetTableId(); resourceAccessTable.Keys.Caller = worldService.Web3.TransactionManager.Account.Address; var record = await worldService.GetRecordTableQueryAsync(resourceAccessTable); Assert.True(record.Values.Access); //then another account - var receipt3 = await accessSystem.GrantAccessRequestAndWaitForReceiptAsync(CounterTable.TableResourceId, UserAccount); + var receipt3 = await accessSystem.GrantAccessRequestAndWaitForReceiptAsync(TableIdRegistry.GetTableId(), UserAccount); resourceAccessTable.Keys.Caller = UserAccount; record = await worldService.GetRecordTableQueryAsync(resourceAccessTable); Assert.True(record.Values.Access); //we can now set the value using the user account directly in the table counter var counterTable = new CounterTable(); - counterTable.Values.Value = 2000; + counterTable.Values.Value = 2500; var worldServiceUser = GetUserWorldService(); receipt3 = await worldServiceUser.SetRecordRequestAndWaitForReceiptAsync(counterTable); var recordCounter = await worldService.GetRecordTableQueryAsync(new CounterTable()); - Assert.True(recordCounter.Values.Value == 2000); + Assert.True(recordCounter.Values.Value == 2500); //revoke access - var receipt4 = await accessSystem.RevokeAccessRequestAndWaitForReceiptAsync(CounterTable.TableResourceId, UserAccount); + var receipt4 = await accessSystem.RevokeAccessRequestAndWaitForReceiptAsync(TableIdRegistry.GetTableId(), UserAccount); //we cannot set the value anymore var counterTable2 = new CounterTable(); @@ -183,7 +193,7 @@ record = await worldService.GetRecordTableQueryAsync(new CounterTable()); //the value should have been incremented by 1 of the previous value we set 2000 - Assert.True(recordCounter.Values.Value == 2001); + Assert.True(recordCounter.Values.Value == 2501); } @@ -197,7 +207,7 @@ public CounterTable() : base("Counter") } public class CounterValue { - [Parameter("int32", 1)] + [Parameter("uint32", 1)] public int Value { get; set; } } @@ -231,10 +241,6 @@ public class ItemValue } } - - - - [Fact] public async Task ShouldSetRecord() { @@ -277,7 +283,171 @@ public async Task ShouldSetRecordTable() var record = await worldService.GetRecordQueryAsync("Counter"); } - + [Fact] + public async Task ShouldGetSetRecordsFromLogs() + { + var web3 = GetWeb3(); + var storeLogProcessingService = new StoreEventsLogProcessing(web3); + var setRecords = await storeLogProcessingService.GetAllSetRecordForTableAndContract(WorldAddress, "Counter", null, null, CancellationToken.None); + + var counterTable0 = new CounterTable(); + counterTable0.DecodeValues(setRecords[0].Event.StaticData, setRecords[0].Event.EncodedLengths, setRecords[0].Event.DynamicData); + Assert.True(counterTable0.Values.Value > 0); + + var counterTable1 = new CounterTable(); + counterTable1.DecodeValues(setRecords[1].Event.StaticData, setRecords[1].Event.EncodedLengths, setRecords[1].Event.DynamicData); + Assert.True(counterTable0.Values.Value > 0); + + foreach (var setRecord in setRecords) + { + var counterTable = new CounterTable(); + counterTable.DecodeValues(setRecord.Event.StaticData, setRecord.Event.EncodedLengths, setRecord.Event.DynamicData); + Debug.WriteLine(counterTable.Values.Value); + Assert.True(counterTable.Values.Value > 0); + } + + } + + + [Fact] + public async Task ShouldGetAllChanges() + { + var web3 = GetWeb3(); + var storeLogProcessingService = new StoreEventsLogProcessing(web3); + var inMemoryStore = new InMemoryTableRepository(); + var tableId = new CounterTable().ResourceId; + await storeLogProcessingService.ProcessAllStoreChangesAsync(inMemoryStore, WorldAddress, null, null, CancellationToken.None); + var results = await inMemoryStore.GetTableRecordsAsync(tableId); + + Assert.True(results.ToList()[0].Values.Value> 0); + + var resultsSystems = await inMemoryStore.GetTableRecordsAsync(new SystemsTableRecord().ResourceId); + Assert.True(resultsSystems.ToList().Count > 0); + foreach (var result in resultsSystems) + { + Debug.WriteLine(ResourceEncoder.Decode(result.Keys.SystemId).Name); + Debug.WriteLine(ResourceEncoder.Decode(result.Keys.SystemId).Namespace); + } + + var resultsAccess = await inMemoryStore.GetTableRecordsAsync(new ResourceAccessTableRecord().ResourceId); + Assert.True(resultsAccess.ToList().Count > 0); + foreach (var result in resultsAccess) + { + Debug.WriteLine(ResourceEncoder.Decode(result.Keys.ResourceId).Name); + Debug.WriteLine(result.Keys.Caller); + Debug.WriteLine(result.Values.Access); + } + + + //the world factory is the owner of the store and world namespaces + var namespaceOwner = await inMemoryStore.GetTableRecordsAsync(new NamespaceOwnerTableRecord().ResourceId); + Assert.True(namespaceOwner.ToList().Count > 0); + foreach (var result in namespaceOwner) + { + Debug.WriteLine(ResourceEncoder.Decode(result.Keys.NamespaceId).Name); + Debug.WriteLine(ResourceEncoder.Decode(result.Keys.NamespaceId).Namespace); + Debug.WriteLine(result.Values.Owner); + } + + var itemTableResults = await inMemoryStore.GetTableRecordsAsync(new ItemTable().ResourceId); + Assert.True(itemTableResults.ToList().Count >= 0); // we many not have set a record yet + foreach (var result in itemTableResults) + { + Debug.WriteLine(result.Keys.Id); + Debug.WriteLine(result.Values.Name); + Debug.WriteLine(result.Values.Price); + Debug.WriteLine(result.Values.Description); + Debug.WriteLine(result.Values.Owner); + } + + } + + [Fact] + public async Task ShouldGetAllChangesForASingleTable() + { + var web3 = GetWeb3(); + var storeLogProcessingService = new StoreEventsLogProcessing(web3); + var inMemoryStore = new InMemoryTableRepository(); + var tableId = new CounterTable().ResourceId; + await storeLogProcessingService.ProcessAllStoreChangesAsync(inMemoryStore, WorldAddress, tableId, null, null, CancellationToken.None); + var results = await inMemoryStore.GetTableRecordsAsync(tableId); + + Assert.True(results.ToList()[0].Values.Value > 0); + + } + + [Fact] + public async Task ShouldGetAllTablesRegistered() + { + var web3 = GetWeb3(); + var storeLogProcessingService = new StoreEventsLogProcessing(web3); + var inMemoryStore = new InMemoryTableRepository(); + var tableId = new TablesTableRecord().ResourceId; + await storeLogProcessingService.ProcessAllStoreChangesAsync(inMemoryStore, WorldAddress, tableId, null, null, CancellationToken.None); + var results = await inMemoryStore.GetTableRecordsAsync(tableId); + + Assert.True(results.ToList().Count > 0); + + foreach (var result in results) + { + var recordTableId = result.Keys.GetTableIdResource(); + + if(recordTableId.Name == "Counter") + { + Assert.True(recordTableId.IsRoot); + var field = result.Values.GetValueSchemaFields().ToList()[0]; + Assert.Equal("uint32", field.Type); + Assert.Equal(1, field.Order); + Assert.Equal("value", field.Name); + } + + if(recordTableId.Name == "Item") + { + Assert.True(recordTableId.IsRoot); + var fields = result.Values.GetValueSchemaFields().ToList(); + + Assert.Equal("uint32", fields[0].Type); + Assert.Equal(1, fields[0].Order); + Assert.Equal("price", fields[0].Name); + Assert.Equal("string", fields[1].Type); + Assert.Equal(2, fields[1].Order); + Assert.Equal("name", fields[1].Name); + Assert.Equal("string", fields[2].Type); + Assert.Equal(3, fields[2].Order); + Assert.Equal("description", fields[2].Name); + Assert.Equal("string", fields[3].Type); + Assert.Equal(4, fields[3].Order); + Assert.Equal("owner", fields[3].Name); + + var keys = result.Values.GetKeySchemaFields().ToList(); + Assert.Equal("uint32", keys[0].Type); + Assert.Equal(1, keys[0].Order); + Assert.Equal("id", keys[0].Name); + + } + + Debug.WriteLine(recordTableId.Name); + Debug.WriteLine(recordTableId.Namespace); + Debug.WriteLine("Field schema"); + foreach (var field in result.Values.GetValueSchemaFields()) + { + Debug.WriteLine(field.Name); + Debug.WriteLine(field.Type); + Debug.WriteLine(field.Order); + + } + Debug.WriteLine("Key Schema"); + foreach (var field in result.Values.GetKeySchemaFields()) + { + Debug.WriteLine(field.Name); + Debug.WriteLine(field.Type); + Debug.WriteLine(field.Order); + } + + } + } + + diff --git a/tests/Nethereum.Mud.UnitTests/KeyEncoderDecoderTest.cs b/tests/Nethereum.Mud.UnitTests/KeyEncoderDecoderTest.cs index 5cb718b26..ea7e67a17 100644 --- a/tests/Nethereum.Mud.UnitTests/KeyEncoderDecoderTest.cs +++ b/tests/Nethereum.Mud.UnitTests/KeyEncoderDecoderTest.cs @@ -1,12 +1,13 @@ using Nethereum.ABI.FunctionEncoding.Attributes; using Nethereum.Hex.HexConvertors.Extensions; +using Nethereum.Mud.EncodingDecoding; using Nethereum.Util; using System.Numerics; namespace Nethereum.Mud.UnitTests { - + public class KeyEncoderDecoderTest diff --git a/tests/Nethereum.Mud.UnitTests/ResourceTests.cs b/tests/Nethereum.Mud.UnitTests/ResourceTests.cs index 314243a12..1144d87cb 100644 --- a/tests/Nethereum.Mud.UnitTests/ResourceTests.cs +++ b/tests/Nethereum.Mud.UnitTests/ResourceTests.cs @@ -1,4 +1,5 @@ using Nethereum.Hex.HexConvertors.Extensions; +using Nethereum.Mud.EncodingDecoding; namespace Nethereum.Mud.UnitTests { diff --git a/tests/Nethereum.Mud.UnitTests/SchemaTypesTests.cs b/tests/Nethereum.Mud.UnitTests/SchemaTypesTests.cs index 2b7146c47..41ee47417 100644 --- a/tests/Nethereum.Mud.UnitTests/SchemaTypesTests.cs +++ b/tests/Nethereum.Mud.UnitTests/SchemaTypesTests.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Numerics; using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Mud.EncodingDecoding; namespace Nethereum.Mud.UnitTests