Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename SYSCALLs #1362

Merged
merged 7 commits into from
Dec 15, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace Neo.SmartContract
{
internal static class StackItemSerializer
internal static class BinarySerializer
{
public static StackItem Deserialize(byte[] data, uint maxItemSize, ReferenceCounter referenceCounter = null)
{
Expand Down
45 changes: 45 additions & 0 deletions src/neo/SmartContract/InteropService.0.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Neo.VM;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Neo.SmartContract
{
public static partial class InteropService
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
{
private static readonly Dictionary<uint, InteropDescriptor> methods = new Dictionary<uint, InteropDescriptor>();

public static long GetPrice(uint hash, EvaluationStack stack)
{
return methods[hash].GetPrice(stack);
}

public static Dictionary<uint, string> SupportedMethods()
{
return methods.ToDictionary(p => p.Key, p => p.Value.Method);
}

internal static bool Invoke(ApplicationEngine engine, uint method)
{
if (!methods.TryGetValue(method, out InteropDescriptor descriptor))
return false;
if (!descriptor.AllowedTriggers.HasFlag(engine.Trigger))
return false;
return descriptor.Handler(engine);
}

private static uint Register(string method, Func<ApplicationEngine, bool> handler, long price, TriggerType allowedTriggers)
{
InteropDescriptor descriptor = new InteropDescriptor(method, handler, price, allowedTriggers);
methods.Add(descriptor.Hash, descriptor);
return descriptor.Hash;
}

private static uint Register(string method, Func<ApplicationEngine, bool> handler, Func<EvaluationStack, long> priceCalculator, TriggerType allowedTriggers)
{
InteropDescriptor descriptor = new InteropDescriptor(method, handler, priceCalculator, allowedTriggers);
methods.Add(descriptor.Hash, descriptor);
return descriptor.Hash;
}
}
}
47 changes: 47 additions & 0 deletions src/neo/SmartContract/InteropService.Binary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using Neo.VM;
using Neo.VM.Types;
using System;
using System.IO;

namespace Neo.SmartContract
{
partial class InteropService
{
public static readonly uint System_Binary_Serialize = Register("System.Binary.Serialize", Binary_Serialize, 0_00100000, TriggerType.All);
public static readonly uint System_Binary_Deserialize = Register("System.Binary.Deserialize", Binary_Deserialize, 0_00500000, TriggerType.All);

private static bool Binary_Serialize(ApplicationEngine engine)
{
byte[] serialized;
try
{
serialized = BinarySerializer.Serialize(engine.CurrentContext.EvaluationStack.Pop(), engine.MaxItemSize);
}
catch
{
return false;
}
engine.CurrentContext.EvaluationStack.Push(serialized);
return true;
}

private static bool Binary_Deserialize(ApplicationEngine engine)
{
StackItem item;
try
{
item = BinarySerializer.Deserialize(engine.CurrentContext.EvaluationStack.Pop().GetSpan(), engine.MaxItemSize, engine.ReferenceCounter);
}
catch (FormatException)
{
return false;
}
catch (IOException)
{
return false;
}
engine.CurrentContext.EvaluationStack.Push(item);
return true;
}
}
}
104 changes: 104 additions & 0 deletions src/neo/SmartContract/InteropService.Blockchain.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using Neo.Ledger;
using Neo.Network.P2P.Payloads;
using Neo.VM;
using Neo.VM.Types;
using System;
using System.Numerics;

namespace Neo.SmartContract
{
partial class InteropService
{
public static readonly uint System_Blockchain_GetHeight = Register("System.Blockchain.GetHeight", Blockchain_GetHeight, 0_00000400, TriggerType.Application);
public static readonly uint System_Blockchain_GetBlock = Register("System.Blockchain.GetBlock", Blockchain_GetBlock, 0_02500000, TriggerType.Application);
public static readonly uint System_Blockchain_GetTransaction = Register("System.Blockchain.GetTransaction", Blockchain_GetTransaction, 0_01000000, TriggerType.Application);
public static readonly uint System_Blockchain_GetTransactionHeight = Register("System.Blockchain.GetTransactionHeight", Blockchain_GetTransactionHeight, 0_01000000, TriggerType.Application);
public static readonly uint System_Blockchain_GetTransactionFromBlock = Register("System.Blockchain.GetTransactionFromBlock", Blockchain_GetTransactionFromBlock, 0_01000000, TriggerType.Application);
public static readonly uint System_Blockchain_GetContract = Register("System.Blockchain.GetContract", Blockchain_GetContract, 0_01000000, TriggerType.Application);

private static bool Blockchain_GetHeight(ApplicationEngine engine)
{
engine.CurrentContext.EvaluationStack.Push(engine.Snapshot.Height);
return true;
}

private static bool Blockchain_GetBlock(ApplicationEngine engine)
{
ReadOnlySpan<byte> data = engine.CurrentContext.EvaluationStack.Pop().GetSpan();
UInt256 hash;
if (data.Length <= 5)
hash = Blockchain.Singleton.GetBlockHash((uint)new BigInteger(data));
else if (data.Length == 32)
hash = new UInt256(data);
else
return false;

Block block = hash != null ? engine.Snapshot.GetBlock(hash) : null;
if (block == null)
engine.CurrentContext.EvaluationStack.Push(StackItem.Null);
else
engine.CurrentContext.EvaluationStack.Push(block.ToStackItem(engine.ReferenceCounter));
return true;
}

private static bool Blockchain_GetTransaction(ApplicationEngine engine)
{
ReadOnlySpan<byte> hash = engine.CurrentContext.EvaluationStack.Pop().GetSpan();
Transaction tx = engine.Snapshot.GetTransaction(new UInt256(hash));
if (tx == null)
engine.CurrentContext.EvaluationStack.Push(StackItem.Null);
else
engine.CurrentContext.EvaluationStack.Push(tx.ToStackItem(engine.ReferenceCounter));
return true;
}

private static bool Blockchain_GetTransactionHeight(ApplicationEngine engine)
{
ReadOnlySpan<byte> hash = engine.CurrentContext.EvaluationStack.Pop().GetSpan();
var tx = engine.Snapshot.Transactions.TryGet(new UInt256(hash));
engine.CurrentContext.EvaluationStack.Push(tx != null ? new BigInteger(tx.BlockIndex) : BigInteger.MinusOne);
return true;
}

private static bool Blockchain_GetTransactionFromBlock(ApplicationEngine engine)
{
ReadOnlySpan<byte> data = engine.CurrentContext.EvaluationStack.Pop().GetSpan();
UInt256 hash;
if (data.Length <= 5)
hash = Blockchain.Singleton.GetBlockHash((uint)new BigInteger(data));
else if (data.Length == 32)
hash = new UInt256(data);
else
return false;

TrimmedBlock block = hash != null ? engine.Snapshot.Blocks.TryGet(hash) : null;
if (block == null)
{
engine.CurrentContext.EvaluationStack.Push(StackItem.Null);
}
else
{
int index = (int)engine.CurrentContext.EvaluationStack.Pop().GetBigInteger();
if (index < 0 || index >= block.Hashes.Length - 1) return false;

Transaction tx = engine.Snapshot.GetTransaction(block.Hashes[index + 1]);
if (tx == null)
engine.CurrentContext.EvaluationStack.Push(StackItem.Null);
else
engine.CurrentContext.EvaluationStack.Push(tx.ToStackItem(engine.ReferenceCounter));
}
return true;
}

private static bool Blockchain_GetContract(ApplicationEngine engine)
{
UInt160 hash = new UInt160(engine.CurrentContext.EvaluationStack.Pop().GetSpan());
ContractState contract = engine.Snapshot.Contracts.TryGet(hash);
if (contract == null)
engine.CurrentContext.EvaluationStack.Push(StackItem.Null);
else
engine.CurrentContext.EvaluationStack.Push(contract.ToStackItem(engine.ReferenceCounter));
return true;
}
}
}
150 changes: 150 additions & 0 deletions src/neo/SmartContract/InteropService.Contract.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
using Neo.IO;
using Neo.Ledger;
using Neo.SmartContract.Manifest;
using Neo.VM;
using Neo.VM.Types;
using System.Linq;

namespace Neo.SmartContract
{
partial class InteropService
{
public static readonly uint System_Contract_Create = Register("System.Contract.Create", Contract_Create, GetDeploymentPrice, TriggerType.Application);
public static readonly uint System_Contract_Update = Register("System.Contract.Update", Contract_Update, GetDeploymentPrice, TriggerType.Application);
public static readonly uint System_Contract_Destroy = Register("System.Contract.Destroy", Contract_Destroy, 0_01000000, TriggerType.Application);
public static readonly uint System_Contract_Call = Register("System.Contract.Call", Contract_Call, 0_01000000, TriggerType.System | TriggerType.Application);
public static readonly uint System_Contract_IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.All);

private static long GetDeploymentPrice(EvaluationStack stack)
{
int size = stack.Peek(0).GetByteLength() + stack.Peek(1).GetByteLength();
return GasPerByte * size;
}

private static bool Contract_Create(ApplicationEngine engine)
{
byte[] script = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray();
if (script.Length > 1024 * 1024) return false;

var manifest = engine.CurrentContext.EvaluationStack.Pop().GetString();
if (manifest.Length > ContractManifest.MaxLength) return false;

UInt160 hash = script.ToScriptHash();
ContractState contract = engine.Snapshot.Contracts.TryGet(hash);
if (contract != null) return false;
contract = new ContractState
{
Script = script,
Manifest = ContractManifest.Parse(manifest)
};

if (!contract.Manifest.IsValid(hash)) return false;

engine.Snapshot.Contracts.Add(hash, contract);
engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(contract));
return true;
}

private static bool Contract_Update(ApplicationEngine engine)
{
byte[] script = engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray();
if (script.Length > 1024 * 1024) return false;
var manifest = engine.CurrentContext.EvaluationStack.Pop().GetString();
if (manifest.Length > ContractManifest.MaxLength) return false;

var contract = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash);
if (contract is null) return false;

if (script.Length > 0)
{
UInt160 hash_new = script.ToScriptHash();
if (hash_new.Equals(engine.CurrentScriptHash)) return false;
if (engine.Snapshot.Contracts.TryGet(hash_new) != null) return false;
contract = new ContractState
{
Script = script,
Manifest = contract.Manifest
};
contract.Manifest.Abi.Hash = hash_new;
engine.Snapshot.Contracts.Add(hash_new, contract);
if (contract.HasStorage)
{
foreach (var (key, value) in engine.Snapshot.Storages.Find(engine.CurrentScriptHash.ToArray()).ToArray())
{
engine.Snapshot.Storages.Add(new StorageKey
{
ScriptHash = hash_new,
Key = key.Key
}, new StorageItem
{
Value = value.Value,
IsConstant = false
});
}
}
Contract_Destroy(engine);
}
if (manifest.Length > 0)
{
contract = engine.Snapshot.Contracts.GetAndChange(contract.ScriptHash);
contract.Manifest = ContractManifest.Parse(manifest);
if (!contract.Manifest.IsValid(contract.ScriptHash)) return false;
if (!contract.HasStorage && engine.Snapshot.Storages.Find(engine.CurrentScriptHash.ToArray()).Any()) return false;
}

return true;
}

private static bool Contract_Destroy(ApplicationEngine engine)
{
UInt160 hash = engine.CurrentScriptHash;
ContractState contract = engine.Snapshot.Contracts.TryGet(hash);
if (contract == null) return true;
engine.Snapshot.Contracts.Delete(hash);
if (contract.HasStorage)
foreach (var (key, _) in engine.Snapshot.Storages.Find(hash.ToArray()))
engine.Snapshot.Storages.Delete(key);
return true;
}

private static bool Contract_Call(ApplicationEngine engine)
{
StackItem contractHash = engine.CurrentContext.EvaluationStack.Pop();

ContractState contract = engine.Snapshot.Contracts.TryGet(new UInt160(contractHash.GetSpan()));
if (contract is null) return false;

StackItem method = engine.CurrentContext.EvaluationStack.Pop();
StackItem args = engine.CurrentContext.EvaluationStack.Pop();
ContractManifest currentManifest = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash)?.Manifest;

if (currentManifest != null && !currentManifest.CanCall(contract.Manifest, method.GetString()))
return false;

if (engine.InvocationCounter.TryGetValue(contract.ScriptHash, out var counter))
{
engine.InvocationCounter[contract.ScriptHash] = counter + 1;
}
else
{
engine.InvocationCounter[contract.ScriptHash] = 1;
}

UInt160 callingScriptHash = engine.CurrentScriptHash;
ExecutionContext context_new = engine.LoadScript(contract.Script, 1);
context_new.GetState<ExecutionContextState>().CallingScriptHash = callingScriptHash;
context_new.EvaluationStack.Push(args);
context_new.EvaluationStack.Push(method);
return true;
}

private static bool Contract_IsStandard(ApplicationEngine engine)
{
UInt160 hash = new UInt160(engine.CurrentContext.EvaluationStack.Pop().GetSpan());
ContractState contract = engine.Snapshot.Contracts.TryGet(hash);
bool isStandard = contract is null || contract.Script.IsStandardContract();
engine.CurrentContext.EvaluationStack.Push(isStandard);
return true;
}
}
}
Loading