Skip to content

Commit

Permalink
change smart contract GetRandom at will
Browse files Browse the repository at this point in the history
  • Loading branch information
Hecate2 committed Aug 30, 2022
1 parent 46a68e7 commit 08cafee
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 84 deletions.
8 changes: 4 additions & 4 deletions Fairy.Debugger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ protected virtual JToken DebugFunctionWithSession(JArray _params)
FairyEngine.Log += CacheLog;
BreakReason breakReason = BreakReason.None;
if (testSession.timestamp == 0)
newEngine = DebugRun(script, testSession.engine.Snapshot.CreateSnapshot(), out breakReason, container: tx, settings: system.Settings, gas: settings.MaxGasInvoke);
newEngine = DebugRun(script, testSession.engine.Snapshot.CreateSnapshot(), out breakReason, container: tx, settings: system.Settings, gas: settings.MaxGasInvoke, oldEngine: testSession.engine);
else
newEngine = DebugRun(script, testSession.engine.Snapshot.CreateSnapshot(), out breakReason, persistingBlock: CreateDummyBlockWithTimestamp(testSession.engine.Snapshot, system.Settings, timestamp: testSession.timestamp), container: tx, settings: system.Settings, gas: settings.MaxGasInvoke);
newEngine = DebugRun(script, testSession.engine.Snapshot.CreateSnapshot(), out breakReason, persistingBlock: CreateDummyBlockWithTimestamp(testSession.engine.Snapshot, system.Settings, timestamp: testSession.timestamp), container: tx, settings: system.Settings, gas: settings.MaxGasInvoke, oldEngine: testSession.engine);
FairyEngine.Log -= CacheLog;
if (writeSnapshot)
sessionStringToFairySession[session].debugEngine = newEngine;
Expand Down Expand Up @@ -139,10 +139,10 @@ private JObject DumpDebugResultJson(FairyEngine newEngine, BreakReason breakReas
return DumpDebugResultJson(new JObject(), newEngine, breakReason);
}

private FairyEngine DebugRun(byte[] script, DataCache snapshot, out BreakReason breakReason, IVerifiable? container = null, Block? persistingBlock = null, ProtocolSettings? settings = null, int offset = 0, long gas = FairyEngine.TestModeGas, IDiagnostic? diagnostic = null)
private FairyEngine DebugRun(byte[] script, DataCache snapshot, out BreakReason breakReason, IVerifiable? container = null, Block? persistingBlock = null, ProtocolSettings? settings = null, int offset = 0, long gas = FairyEngine.TestModeGas, IDiagnostic? diagnostic = null, FairyEngine oldEngine = null)
{
persistingBlock ??= CreateDummyBlockWithTimestamp(snapshot, settings ?? ProtocolSettings.Default, timestamp: 0);
FairyEngine engine = FairyEngine.Create(TriggerType.Application, container, snapshot, persistingBlock, settings, gas, diagnostic);
FairyEngine engine = FairyEngine.Create(TriggerType.Application, container, snapshot, persistingBlock, settings, gas, diagnostic, oldEngine: oldEngine);
engine.LoadScript(script, initialPosition: offset);
return Execute(engine, out breakReason);
}
Expand Down
128 changes: 119 additions & 9 deletions Fairy.Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,32 @@
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.VM;
using System.Numerics;
using System.Reflection;

namespace Neo.Plugins
{
public partial class Fairy
{
public class FairyEngine : ApplicationEngine
{
protected FairyEngine(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, ProtocolSettings settings, long gas, IDiagnostic diagnostic) : base(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic){}
protected FairyEngine(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, ProtocolSettings settings, long gas, IDiagnostic diagnostic, FairyEngine oldEngine = null) : base(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic)
{
if (oldEngine != null)
{
this.services = oldEngine.services;
this.serviceArgs = oldEngine.serviceArgs;
}
else
{
this.services = ApplicationEngine.Services.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
this.serviceArgs = new ServiceArgs();
}
}

public static new FairyEngine Create(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock = null, ProtocolSettings settings = null, long gas = TestModeGas, IDiagnostic diagnostic = null)
public static FairyEngine Create(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock = null, ProtocolSettings settings = null, long gas = TestModeGas, IDiagnostic diagnostic = null, FairyEngine oldEngine = null)
{
return new FairyEngine(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic);
return new FairyEngine(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic, oldEngine: oldEngine);
}

public new VMState State
Expand All @@ -35,14 +49,80 @@ protected FairyEngine(TriggerType trigger, IVerifiable container, DataCache snap
base.ExecuteNext();
}

public static new FairyEngine Run(ReadOnlyMemory<byte> script, DataCache snapshot, IVerifiable container = null, Block persistingBlock = null, ProtocolSettings settings = null, int offset = 0, long gas = TestModeGas, IDiagnostic diagnostic = null)
public static new FairyEngine Run(ReadOnlyMemory<byte> script, DataCache snapshot, IVerifiable container = null, Block persistingBlock = null, ProtocolSettings settings = null, int offset = 0, long gas = TestModeGas, IDiagnostic diagnostic = null, FairyEngine oldEngine = null)
{
persistingBlock ??= CreateDummyBlockWithTimestamp(snapshot, settings ?? ProtocolSettings.Default, timestamp: 0);
FairyEngine engine = Create(TriggerType.Application, container, snapshot, persistingBlock, settings, gas, diagnostic);
FairyEngine engine = Create(TriggerType.Application, container, snapshot, persistingBlock, settings, gas, diagnostic, oldEngine: oldEngine);
engine.LoadScript(script, initialPosition: offset);
engine.Execute();
return engine;
}

public Dictionary<uint, InteropDescriptor> services;

public class ServiceArgs
{
public BigInteger? designatedRandom = null;
}
public ServiceArgs serviceArgs;

protected override void OnSysCall(uint method)
{
OnSysCall(this.services[method]);
}

public InteropDescriptor Register(string name, MethodInfo method, uint hash, long fixedPrice, CallFlags requiredCallFlags)
{
InteropDescriptor descriptor = new()
{
Name = name,
Handler = method,
FixedPrice = fixedPrice,
RequiredCallFlags = requiredCallFlags
};
this.services ??= new Dictionary<uint, InteropDescriptor>();
this.services[hash] = descriptor;
return descriptor;
}

public new BigInteger GetRandom() => base.GetRandom();
public BigInteger GetFairyRandom()
{
if (serviceArgs.designatedRandom != null)
return (BigInteger)serviceArgs.designatedRandom;
return GetRandom();
}
}


[RpcMethod]
protected virtual JToken SetSnapshotRandom(JArray _params)
{
string session = _params[0].AsString();
string? designatedRandomString = _params[1]?.AsString();
FairySession fairySession = sessionStringToFairySession[session];
if (designatedRandomString == null)
fairySession.designatedRandom = null;
else
fairySession.designatedRandom = BigInteger.Parse(designatedRandomString);
JObject json = new();
json[session] = designatedRandomString;
return json;
}

[RpcMethod]
protected virtual JToken GetSnapshotRandom(JArray _params)
{
JObject json = new();
foreach (var s in _params)
{
string session = s.AsString();
if (sessionStringToFairySession.ContainsKey(session))
json[session] = sessionStringToFairySession[session].designatedRandom.ToString();
else
json[session] = null;
}
return json;
}

private static Block CreateDummyBlockWithTimestamp(DataCache snapshot, ProtocolSettings settings, ulong timestamp = 0)
Expand Down Expand Up @@ -73,12 +153,42 @@ public class FairySession
{
public DateTime StartTime;
public FairyEngine engine { get { ResetExpiration(); return _engine; } set { _engine = value; ResetExpiration(); } }
public FairyEngine _engine;
private FairyEngine _engine;
public FairyEngine? debugEngine { get { ResetExpiration(); return _debugEngine; } set { _debugEngine = value; ResetExpiration(); } }
public FairyEngine? _debugEngine = null;
private FairyEngine? _debugEngine = null;
public ulong timestamp { get { ResetExpiration(); return _timestamp; } set { _timestamp = value; ResetExpiration(); } }
public ulong _timestamp = 0;
// public BigInteger? designatedRandom = null;
private ulong _timestamp = 0;

public BigInteger? designatedRandom
{
get
{
ResetExpiration();
return engine.serviceArgs.designatedRandom;
}
set
{
if (value == null)
{
engine.Register("System.Runtime.GetRandom", typeof(FairyEngine).GetMethod(nameof(FairyEngine.GetRandom)), ApplicationEngine.System_Runtime_GetRandom.Hash, 0, CallFlags.None);
engine.serviceArgs.designatedRandom = null;
}
else
{
engine.serviceArgs.designatedRandom = value;
engine.Register("System.Runtime.GetRandom", typeof(FairyEngine).GetMethod(nameof(FairyEngine.GetFairyRandom)), ApplicationEngine.System_Runtime_GetRandom.Hash, 0, CallFlags.None);
}
ResetExpiration();
}
}

public void ResetServices()
{
engine.serviceArgs = new();
_timestamp = 0;
engine.services = ApplicationEngine.Services.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
ResetExpiration();
}

public FairySession(Fairy fairy)
{
Expand Down
40 changes: 1 addition & 39 deletions Fairy.Tester.Snapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public FairySession NewTestSession()

private FairyEngine BuildSnapshotWithDummyScript(FairyEngine engine = null)
{
return FairyEngine.Run(new byte[] { 0x40 }, engine != null ? engine.Snapshot.CreateSnapshot() : system.StoreView, settings: system.Settings, gas: settings.MaxGasInvoke);
return FairyEngine.Run(new byte[] { 0x40 }, engine != null ? engine.Snapshot.CreateSnapshot() : system.StoreView, settings: system.Settings, gas: settings.MaxGasInvoke, oldEngine: engine);
}

[RpcMethod]
Expand Down Expand Up @@ -103,43 +103,5 @@ protected virtual JToken GetSnapshotTimeStamp(JArray _params)
}
return json;
}

//[RpcMethod]
//protected virtual JToken SetSnapshotRandom(JArray _params)
//{
// string session = _params[0].AsString();
// string? designatedRandomString = _params[1]?.AsString();
// if (designatedRandomString == null)
// {
// RuntimeArgs runtimeArgs = sessionToRuntimeArgs[session];
// runtimeArgs.designatedRandom = null;
// sessionToRuntimeArgs[session] = runtimeArgs;
// }
// else
// {
// BigInteger designatedRandom = BigInteger.Parse(designatedRandomString);
// RuntimeArgs runtimeArgs = sessionToRuntimeArgs[session];
// runtimeArgs.designatedRandom = designatedRandom;
// sessionToRuntimeArgs[session] = runtimeArgs;
// }
// JObject json = new();
// json[session] = designatedRandomString;
// return json;
//}

//[RpcMethod]
//protected virtual JToken GetSnapshotRandom(JArray _params)
//{
// JObject json = new();
// foreach (var s in _params)
// {
// string session = s.AsString();
// if (sessionToRuntimeArgs.ContainsKey(session))
// json[session] = sessionToRuntimeArgs[session].designatedRandom.ToString();
// else
// json[session] = null;
// }
// return json;
//}
}
}
4 changes: 2 additions & 2 deletions Fairy.Tester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ private JObject GetInvokeResultWithSession(string session, bool writeSnapshot, b
logs.Clear();
FairyEngine.Log += CacheLog;
if (testSession.timestamp == 0)
newEngine = FairyEngine.Run(script, testSession.engine.Snapshot.CreateSnapshot(), container: tx, settings: system.Settings, gas: settings.MaxGasInvoke);
newEngine = FairyEngine.Run(script, testSession.engine.Snapshot.CreateSnapshot(), container: tx, settings: system.Settings, gas: settings.MaxGasInvoke, oldEngine: oldEngine);
else
{
block = CreateDummyBlockWithTimestamp(testSession.engine.Snapshot, system.Settings, timestamp: testSession.timestamp);
newEngine = FairyEngine.Run(script, testSession.engine.Snapshot.CreateSnapshot(), persistingBlock: block, container: tx, settings: system.Settings, gas: settings.MaxGasInvoke);
newEngine = FairyEngine.Run(script, testSession.engine.Snapshot.CreateSnapshot(), persistingBlock: block, container: tx, settings: system.Settings, gas: settings.MaxGasInvoke, oldEngine: oldEngine);
}
FairyEngine.Log -= CacheLog;
if (writeSnapshot && newEngine.State == VMState.HALT)
Expand Down
31 changes: 1 addition & 30 deletions Fairy.Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ protected virtual JObject VirtualDeploy(JArray _params)
Block dummyBlock = CreateDummyBlockWithTimestamp(testSession.engine.Snapshot, system.Settings, timestamp: sessionStringToFairySession[session].timestamp);
Transaction tx = fairyWallet.MakeTransaction(snapshot.CreateSnapshot(), script, persistingBlock: dummyBlock);
UInt160 hash = SmartContract.Helper.GetContractHash(tx.Sender, nef.CheckSum, manifest.Name);
sessionStringToFairySession[session].engine = FairyEngine.Run(script, snapshot.CreateSnapshot(), persistingBlock: dummyBlock, container: tx, settings: system.Settings, gas: settings.MaxGasInvoke);
sessionStringToFairySession[session].engine = FairyEngine.Run(script, snapshot.CreateSnapshot(), persistingBlock: dummyBlock, container: tx, settings: system.Settings, gas: settings.MaxGasInvoke, oldEngine: sessionStringToFairySession[session].engine);
json[session] = hash.ToString();
}
catch (InvalidOperationException ex)
Expand Down Expand Up @@ -230,35 +230,6 @@ public void SerializeUnsigned(BinaryWriter writer)
}
}

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 FairyEngine engine = FairyEngine.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();
Expand Down

0 comments on commit 08cafee

Please sign in to comment.