-
Notifications
You must be signed in to change notification settings - Fork 100
/
Copy pathUtility.cs
289 lines (265 loc) · 13.3 KB
/
Utility.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
// Copyright (C) 2015-2023 The Neo Project.
//
// The Neo.Network.RPC is free software distributed under the MIT software license,
// see the accompanying file LICENSE in the main directory of the
// project or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
using Neo.Cryptography.ECC;
using Neo.Json;
using Neo.Network.P2P.Payloads;
using Neo.Network.P2P.Payloads.Conditions;
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.VM.Types;
using Neo.Wallets;
using System;
using System.Linq;
using System.Numerics;
using Array = Neo.VM.Types.Array;
using Buffer = Neo.VM.Types.Buffer;
namespace Neo.Network.RPC
{
public static class Utility
{
private static (BigInteger numerator, BigInteger denominator) Fraction(decimal d)
{
int[] bits = decimal.GetBits(d);
BigInteger numerator = (1 - ((bits[3] >> 30) & 2)) *
unchecked(((BigInteger)(uint)bits[2] << 64) |
((BigInteger)(uint)bits[1] << 32) |
(uint)bits[0]);
BigInteger denominator = BigInteger.Pow(10, (bits[3] >> 16) & 0xff);
return (numerator, denominator);
}
public static UInt160 ToScriptHash(this JToken value, ProtocolSettings protocolSettings)
{
var addressOrScriptHash = value.AsString();
return addressOrScriptHash.Length < 40 ?
addressOrScriptHash.ToScriptHash(protocolSettings.AddressVersion) : UInt160.Parse(addressOrScriptHash);
}
public static string AsScriptHash(this string addressOrScriptHash)
{
foreach (var native in NativeContract.Contracts)
{
if (addressOrScriptHash.Equals(native.Name, StringComparison.InvariantCultureIgnoreCase) ||
addressOrScriptHash == native.Id.ToString())
return native.Hash.ToString();
}
return addressOrScriptHash.Length < 40 ?
addressOrScriptHash : UInt160.Parse(addressOrScriptHash).ToString();
}
/// <summary>
/// Parse WIF or private key hex string to KeyPair
/// </summary>
/// <param name="key">WIF or private key hex string
/// Example: WIF ("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p"), PrivateKey ("450d6c2a04b5b470339a745427bae6828400cf048400837d73c415063835e005")</param>
/// <returns></returns>
public static KeyPair GetKeyPair(string key)
{
if (string.IsNullOrEmpty(key)) { throw new ArgumentNullException(nameof(key)); }
if (key.StartsWith("0x")) { key = key[2..]; }
return key.Length switch
{
52 => new KeyPair(Wallet.GetPrivateKeyFromWIF(key)),
64 => new KeyPair(key.HexToBytes()),
_ => throw new FormatException()
};
}
/// <summary>
/// Parse address, scripthash or public key string to UInt160
/// </summary>
/// <param name="account">account address, scripthash or public key string
/// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575")</param>
/// <param name="protocolSettings">The protocol settings</param>
/// <returns></returns>
public static UInt160 GetScriptHash(string account, ProtocolSettings protocolSettings)
{
if (string.IsNullOrEmpty(account)) { throw new ArgumentNullException(nameof(account)); }
if (account.StartsWith("0x")) { account = account[2..]; }
return account.Length switch
{
34 => account.ToScriptHash(protocolSettings.AddressVersion),
40 => UInt160.Parse(account),
66 => Contract.CreateSignatureRedeemScript(ECPoint.Parse(account, ECCurve.Secp256r1)).ToScriptHash(),
_ => throw new FormatException(),
};
}
/// <summary>
/// Convert decimal amount to BigInteger: amount * 10 ^ decimals
/// </summary>
/// <param name="amount">float value</param>
/// <param name="decimals">token decimals</param>
/// <returns></returns>
public static BigInteger ToBigInteger(this decimal amount, uint decimals)
{
BigInteger factor = BigInteger.Pow(10, (int)decimals);
var (numerator, denominator) = Fraction(amount);
if (factor < denominator)
{
throw new ArgumentException("The decimal places is too long.");
}
BigInteger res = factor * numerator / denominator;
return res;
}
public static Block BlockFromJson(JObject json, ProtocolSettings protocolSettings)
{
return new Block()
{
Header = HeaderFromJson(json, protocolSettings),
Transactions = ((JArray)json["tx"]).Select(p => TransactionFromJson((JObject)p, protocolSettings)).ToArray()
};
}
public static JObject BlockToJson(Block block, ProtocolSettings protocolSettings)
{
JObject json = block.ToJson(protocolSettings);
json["tx"] = block.Transactions.Select(p => TransactionToJson(p, protocolSettings)).ToArray();
return json;
}
public static Header HeaderFromJson(JObject json, ProtocolSettings protocolSettings)
{
return new Header
{
Version = (uint)json["version"].AsNumber(),
PrevHash = UInt256.Parse(json["previousblockhash"].AsString()),
MerkleRoot = UInt256.Parse(json["merkleroot"].AsString()),
Timestamp = (ulong)json["time"].AsNumber(),
Nonce = Convert.ToUInt64(json["nonce"].AsString(), 16),
Index = (uint)json["index"].AsNumber(),
PrimaryIndex = (byte)json["primary"].AsNumber(),
NextConsensus = json["nextconsensus"].ToScriptHash(protocolSettings),
Witness = ((JArray)json["witnesses"]).Select(p => WitnessFromJson((JObject)p)).FirstOrDefault()
};
}
public static Transaction TransactionFromJson(JObject json, ProtocolSettings protocolSettings)
{
return new Transaction
{
Version = byte.Parse(json["version"].AsString()),
Nonce = uint.Parse(json["nonce"].AsString()),
Signers = ((JArray)json["signers"]).Select(p => SignerFromJson((JObject)p, protocolSettings)).ToArray(),
SystemFee = long.Parse(json["sysfee"].AsString()),
NetworkFee = long.Parse(json["netfee"].AsString()),
ValidUntilBlock = uint.Parse(json["validuntilblock"].AsString()),
Attributes = ((JArray)json["attributes"]).Select(p => TransactionAttributeFromJson((JObject)p)).ToArray(),
Script = Convert.FromBase64String(json["script"].AsString()),
Witnesses = ((JArray)json["witnesses"]).Select(p => WitnessFromJson((JObject)p)).ToArray()
};
}
public static JObject TransactionToJson(Transaction tx, ProtocolSettings protocolSettings)
{
JObject json = tx.ToJson(protocolSettings);
json["sysfee"] = tx.SystemFee.ToString();
json["netfee"] = tx.NetworkFee.ToString();
return json;
}
public static Signer SignerFromJson(JObject json, ProtocolSettings protocolSettings)
{
return new Signer
{
Account = json["account"].ToScriptHash(protocolSettings),
Rules = ((JArray)json["rules"])?.Select(p => RuleFromJson((JObject)p, protocolSettings)).ToArray(),
Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), json["scopes"].AsString()),
AllowedContracts = ((JArray)json["allowedcontracts"])?.Select(p => p.ToScriptHash(protocolSettings)).ToArray(),
AllowedGroups = ((JArray)json["allowedgroups"])?.Select(p => ECPoint.Parse(p.AsString(), ECCurve.Secp256r1)).ToArray()
};
}
public static TransactionAttribute TransactionAttributeFromJson(JObject json)
{
TransactionAttributeType usage = Enum.Parse<TransactionAttributeType>(json["type"].AsString());
return usage switch
{
TransactionAttributeType.HighPriority => new HighPriorityAttribute(),
TransactionAttributeType.OracleResponse => new OracleResponse()
{
Id = (ulong)json["id"].AsNumber(),
Code = Enum.Parse<OracleResponseCode>(json["code"].AsString()),
Result = Convert.FromBase64String(json["result"].AsString()),
},
_ => throw new FormatException(),
};
}
public static Witness WitnessFromJson(JObject json)
{
return new Witness
{
InvocationScript = Convert.FromBase64String(json["invocation"].AsString()),
VerificationScript = Convert.FromBase64String(json["verification"].AsString())
};
}
public static WitnessRule RuleFromJson(JObject json, ProtocolSettings protocolSettings)
{
return new WitnessRule()
{
Action = Enum.Parse<WitnessRuleAction>(json["action"].AsString()),
Condition = RuleExpressionFromJson((JObject)json["condition"], protocolSettings)
};
}
public static WitnessCondition RuleExpressionFromJson(JObject json, ProtocolSettings protocolSettings)
{
return json["type"].AsString() switch
{
"Or" => new OrCondition { Expressions = ((JArray)json["expressions"])?.Select(p => RuleExpressionFromJson((JObject)p, protocolSettings)).ToArray() },
"And" => new AndCondition { Expressions = ((JArray)json["expressions"])?.Select(p => RuleExpressionFromJson((JObject)p, protocolSettings)).ToArray() },
"Boolean" => new BooleanCondition { Expression = json["expression"].AsBoolean() },
"Not" => new NotCondition { Expression = RuleExpressionFromJson((JObject)json["expression"], protocolSettings) },
"Group" => new GroupCondition { Group = ECPoint.Parse(json["group"].AsString(), ECCurve.Secp256r1) },
"CalledByContract" => new CalledByContractCondition { Hash = json["hash"].ToScriptHash(protocolSettings) },
"ScriptHash" => new ScriptHashCondition { Hash = json["hash"].ToScriptHash(protocolSettings) },
"CalledByEntry" => new CalledByEntryCondition(),
"CalledByGroup" => new CalledByGroupCondition { Group = ECPoint.Parse(json["group"].AsString(), ECCurve.Secp256r1) },
_ => throw new FormatException("Wrong rule's condition type"),
};
}
public static StackItem StackItemFromJson(JObject json)
{
StackItemType type = json["type"].GetEnum<StackItemType>();
switch (type)
{
case StackItemType.Boolean:
return json["value"].GetBoolean() ? StackItem.True : StackItem.False;
case StackItemType.Buffer:
return new Buffer(Convert.FromBase64String(json["value"].AsString()));
case StackItemType.ByteString:
return new ByteString(Convert.FromBase64String(json["value"].AsString()));
case StackItemType.Integer:
return BigInteger.Parse(json["value"].AsString());
case StackItemType.Array:
Array array = new();
foreach (JObject item in (JArray)json["value"])
array.Add(StackItemFromJson(item));
return array;
case StackItemType.Struct:
Struct @struct = new();
foreach (JObject item in (JArray)json["value"])
@struct.Add(StackItemFromJson(item));
return @struct;
case StackItemType.Map:
Map map = new();
foreach (var item in (JArray)json["value"])
{
PrimitiveType key = (PrimitiveType)StackItemFromJson((JObject)item["key"]);
map[key] = StackItemFromJson((JObject)item["value"]);
}
return map;
case StackItemType.Pointer:
return new Pointer(null, (int)json["value"].AsNumber());
case StackItemType.InteropInterface:
return new InteropInterface(json);
default:
return json["value"]?.AsString() ?? StackItem.Null;
}
}
public static string GetIteratorId(this StackItem item)
{
if (item is InteropInterface iop)
{
var json = iop.GetInterface<JObject>();
return json["id"]?.GetString();
}
return null;
}
}
}