-
Notifications
You must be signed in to change notification settings - Fork 100
/
Copy pathRpcServer.SmartContract.cs
190 lines (171 loc) · 6.82 KB
/
RpcServer.SmartContract.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
using Neo.Cryptography.ECC;
using Neo.IO;
using Neo.IO.Json;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract;
using Neo.SmartContract.Iterators;
using Neo.SmartContract.Native;
using Neo.VM;
using Neo.VM.Types;
using Neo.Wallets;
using System;
using System.IO;
using System.Linq;
namespace Neo.Plugins
{
partial class RpcServer
{
private class Signers : IVerifiable
{
private readonly Signer[] _signers;
public Witness[] Witnesses { get; set; }
public int Size => _signers.Length;
public Signers(Signer[] signers)
{
_signers = signers;
}
public void Serialize(BinaryWriter writer)
{
throw new NotImplementedException();
}
public void Deserialize(BinaryReader reader)
{
throw new NotImplementedException();
}
public void DeserializeUnsigned(BinaryReader reader)
{
throw new NotImplementedException();
}
public UInt160[] GetScriptHashesForVerifying(DataCache snapshot)
{
return _signers.Select(p => p.Account).ToArray();
}
public Signer[] GetSigners()
{
return _signers;
}
public void SerializeUnsigned(BinaryWriter writer)
{
throw new NotImplementedException();
}
}
private JObject GetInvokeResult(byte[] script, Signers signers = null)
{
Transaction tx = signers == null ? null : new Transaction
{
Signers = signers.GetSigners(),
Attributes = System.Array.Empty<TransactionAttribute>(),
Witnesses = signers.Witnesses,
};
using ApplicationEngine engine = ApplicationEngine.Run(script, system.StoreView, container: tx, settings: system.Settings, gas: settings.MaxGasInvoke);
JObject json = new();
json["script"] = Convert.ToBase64String(script);
json["state"] = engine.State;
json["gasconsumed"] = engine.GasConsumed.ToString();
json["exception"] = GetExceptionMessage(engine.FaultException);
try
{
json["stack"] = new JArray(engine.ResultStack.Select(p => ToJson(p, settings.MaxIteratorResultItems)));
}
catch (InvalidOperationException)
{
json["stack"] = "error: invalid operation";
}
if (engine.State != VMState.FAULT)
{
ProcessInvokeWithWallet(json, signers);
}
return json;
}
private static JObject ToJson(StackItem item, int max)
{
JObject json = item.ToJson();
if (item is InteropInterface interopInterface && interopInterface.GetInterface<object>() is IIterator iterator)
{
JArray array = new();
while (max > 0 && iterator.Next())
{
array.Add(iterator.Value().ToJson());
max--;
}
json["iterator"] = array;
json["truncated"] = iterator.Next();
}
return json;
}
private static Signers SignersFromJson(JArray _params, ProtocolSettings settings)
{
var ret = new Signers(_params.Select(u => new Signer()
{
Account = AddressToScriptHash(u["account"].AsString(), settings.AddressVersion),
Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), u["scopes"]?.AsString()),
AllowedContracts = ((JArray)u["allowedcontracts"])?.Select(p => UInt160.Parse(p.AsString())).ToArray(),
AllowedGroups = ((JArray)u["allowedgroups"])?.Select(p => ECPoint.Parse(p.AsString(), ECCurve.Secp256r1)).ToArray()
}).ToArray())
{
Witnesses = _params
.Select(u => new
{
Invocation = u["invocation"]?.AsString(),
Verification = u["verification"]?.AsString()
})
.Where(x => x.Invocation != null || x.Verification != null)
.Select(x => new Witness()
{
InvocationScript = Convert.FromBase64String(x.Invocation ?? string.Empty),
VerificationScript = Convert.FromBase64String(x.Verification ?? string.Empty)
}).ToArray()
};
// Validate format
_ = IO.Helper.ToByteArray(ret.GetSigners()).AsSerializableArray<Signer>();
return ret;
}
[RpcMethod]
protected virtual JObject InvokeFunction(JArray _params)
{
UInt160 script_hash = UInt160.Parse(_params[0].AsString());
string operation = _params[1].AsString();
ContractParameter[] args = _params.Count >= 3 ? ((JArray)_params[2]).Select(p => ContractParameter.FromJson(p)).ToArray() : System.Array.Empty<ContractParameter>();
Signers signers = _params.Count >= 4 ? SignersFromJson((JArray)_params[3], system.Settings) : null;
byte[] script;
using (ScriptBuilder sb = new())
{
script = sb.EmitDynamicCall(script_hash, operation, args).ToArray();
}
return GetInvokeResult(script, signers);
}
[RpcMethod]
protected virtual JObject InvokeScript(JArray _params)
{
byte[] script = Convert.FromBase64String(_params[0].AsString());
Signers signers = _params.Count >= 2 ? SignersFromJson((JArray)_params[1], system.Settings) : null;
return GetInvokeResult(script, signers);
}
[RpcMethod]
protected virtual JObject GetUnclaimedGas(JArray _params)
{
string address = _params[0].AsString();
JObject json = new();
UInt160 script_hash;
try
{
script_hash = AddressToScriptHash(address, system.Settings.AddressVersion);
}
catch
{
script_hash = null;
}
if (script_hash == null)
throw new RpcException(-100, "Invalid address");
var snapshot = system.StoreView;
json["unclaimed"] = NativeContract.NEO.UnclaimedGas(snapshot, script_hash, NativeContract.Ledger.CurrentIndex(snapshot) + 1).ToString();
json["address"] = script_hash.ToAddress(system.Settings.AddressVersion);
return json;
}
static string GetExceptionMessage(Exception exception)
{
return exception?.GetBaseException().Message;
}
}
}