-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathGeneratedEventMetadata.cs
109 lines (93 loc) · 4.43 KB
/
GeneratedEventMetadata.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
using Meadow.Core.AbiEncoding;
using Meadow.Core.Cryptography;
using Meadow.Core.Utils;
using SolcNet.DataDescription.Output;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
namespace Meadow.SolCodeGen
{
public class GeneratedEventMetadata
{
public string EventSignatureHash { get; set; }
public string ClrTypeName { get; set; }
public string ClrTypeFullName { get; set; }
public int IndexedArgsCounts { get; set; }
public Abi AbiItem { get; set; }
public static IEnumerable<GeneratedEventMetadata> Parse(string contractName, string @namespace, SolcNet.DataDescription.Output.Contract contract)
{
foreach (var item in contract.Abi)
{
if (item.Type == AbiType.Event)
{
// Check if this event name is overloaded (duplicate events with same name but different types).
var isOverloaded = contract.Abi
.Where(i => i.Type == AbiType.Event)
.Where(i => i.Name == item.Name)
.Where(i => !ReferenceEquals(i, item))
.Any();
string eventName;
if (isOverloaded)
{
string GetInputTypeName(string type)
{
// Format an array type def into name without symbols,
// supporting dynamic and fixed sized types such as:
// uint32[5][7][9] -> uint32Array5Array7Array9
// uint32[5][][9] -> uint32Array5ArrayArray9
// TODO: there is probably a regex to do this better.
return type
.Replace("[]", "Array", StringComparison.Ordinal)
.Trim('[', ']')
.Replace("[", "Array", StringComparison.Ordinal)
.Replace("]", string.Empty, StringComparison.Ordinal);
}
// If the event is overloaded, append the event data types to the name.
eventName = item.Name + "_" + string.Join("_", item.Inputs.Select(i => GetInputTypeName(i.Type)));
}
else
{
eventName = ReservedKeywords.EscapeIdentifier(item.Name);
}
string eventSignatureHash = AbiSignature.GetSignatureHash(item);
yield return new GeneratedEventMetadata
{
AbiItem = item,
EventSignatureHash = eventSignatureHash,
ClrTypeName = eventName,
ClrTypeFullName = $"{@namespace}.{contractName}.{eventName}",
IndexedArgsCounts = item.Inputs.Count(a => a.Indexed.GetValueOrDefault()),
};
}
}
}
/// <summary>
/// Concats all the event metadata signatures and type names and hashes them.
/// </summary>
public static byte[] GetHash(List<GeneratedEventMetadata> items)
{
int bufferSize = 0;
for (var i = 0; i < items.Count; i++)
{
bufferSize += items[i].ClrTypeFullName.Length + items[i].EventSignatureHash.Length + 2;
}
Span<char> inputData = stackalloc char[bufferSize];
Span<char> inputDataCursor = inputData;
for (var i = 0; i < items.Count; i++)
{
items[i].ClrTypeFullName.AsSpan().CopyTo(inputDataCursor);
inputDataCursor = inputDataCursor.Slice(items[i].ClrTypeFullName.Length);
items[i].EventSignatureHash.AsSpan().CopyTo(inputDataCursor);
inputDataCursor = inputDataCursor.Slice(items[i].EventSignatureHash.Length);
items[i].IndexedArgsCounts.ToString("00", CultureInfo.InvariantCulture).AsSpan().CopyTo(inputDataCursor);
inputDataCursor = inputDataCursor.Slice(2);
}
var hashBuffer = new byte[32];
KeccakHash.ComputeHash(MemoryMarshal.AsBytes(inputData), hashBuffer);
return hashBuffer;
}
}
}