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

[NEP4] Feature-dynamic-invoke verification #120

Merged
merged 17 commits into from
Dec 9, 2017
Merged
Show file tree
Hide file tree
Changes from all 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
13 changes: 13 additions & 0 deletions neo/Core/ContractPropertyState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace Neo.Core
{
[Flags]
public enum ContractPropertyState : byte
{
NoProperty = 0,

HasStorage = 1 << 0,
HasDynamicInvoke = 1 << 1,
}
}
19 changes: 13 additions & 6 deletions neo/Core/ContractState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ public class ContractState : StateBase, ICloneable<ContractState>
public byte[] Script;
public ContractParameterType[] ParameterList;
public ContractParameterType ReturnType;
public bool HasStorage;
public ContractPropertyState ContractProperties;
public string Name;
public string CodeVersion;
public string Author;
public string Email;
public string Description;


public bool HasStorage => ContractProperties.HasFlag(ContractPropertyState.HasStorage);

public bool HasDynamicInvoke => ContractProperties.HasFlag(ContractPropertyState.HasDynamicInvoke);

private UInt160 _scriptHash;
public UInt160 ScriptHash
{
Expand All @@ -40,7 +45,7 @@ ContractState ICloneable<ContractState>.Clone()
Script = Script,
ParameterList = ParameterList,
ReturnType = ReturnType,
HasStorage = HasStorage,
ContractProperties = ContractProperties,
Name = Name,
CodeVersion = CodeVersion,
Author = Author,
Expand All @@ -55,7 +60,7 @@ public override void Deserialize(BinaryReader reader)
Script = reader.ReadVarBytes();
ParameterList = reader.ReadVarBytes().Select(p => (ContractParameterType)p).ToArray();
ReturnType = (ContractParameterType)reader.ReadByte();
HasStorage = reader.ReadBoolean();
ContractProperties = (ContractPropertyState)reader.ReadByte();
Name = reader.ReadVarString();
CodeVersion = reader.ReadVarString();
Author = reader.ReadVarString();
Expand All @@ -68,7 +73,7 @@ void ICloneable<ContractState>.FromReplica(ContractState replica)
Script = replica.Script;
ParameterList = replica.ParameterList;
ReturnType = replica.ReturnType;
HasStorage = replica.HasStorage;
ContractProperties = replica.ContractProperties;
Name = replica.Name;
CodeVersion = replica.CodeVersion;
Author = replica.Author;
Expand All @@ -82,7 +87,7 @@ public override void Serialize(BinaryWriter writer)
writer.WriteVarBytes(Script);
writer.WriteVarBytes(ParameterList.Cast<byte>().ToArray());
writer.Write((byte)ReturnType);
writer.Write(HasStorage);
writer.Write((byte)ContractProperties);
writer.WriteVarString(Name);
writer.WriteVarString(CodeVersion);
writer.WriteVarString(Author);
Expand All @@ -97,12 +102,14 @@ public override JObject ToJson()
json["script"] = Script.ToHexString();
json["parameters"] = new JArray(ParameterList.Select(p => (JObject)p));
json["returntype"] = ReturnType;
json["storage"] = HasStorage;
json["name"] = Name;
json["code_version"] = CodeVersion;
json["author"] = Author;
json["email"] = Email;
json["description"] = Description;
json["properties"] = new JObject();
json["properties"]["storage"] = HasStorage;
json["properties"]["dynamic_invoke"] = HasDynamicInvoke;
return json;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ private void Persist(Block block)
Script = publish_tx.Script,
ParameterList = publish_tx.ParameterList,
ReturnType = publish_tx.ReturnType,
HasStorage = publish_tx.NeedStorage,
ContractProperties = (ContractPropertyState)Convert.ToByte(publish_tx.NeedStorage),
Name = publish_tx.Name,
CodeVersion = publish_tx.CodeVersion,
Author = publish_tx.Author,
Expand Down
38 changes: 37 additions & 1 deletion neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public class ApplicationEngine : ExecutionEngine
private long gas_consumed = 0;
private readonly bool testMode;

private readonly CachedScriptTable script_table;

public TriggerType Trigger { get; }
public Fixed8 GasConsumed => new Fixed8(gas_consumed);

Expand All @@ -48,6 +50,10 @@ public ApplicationEngine(TriggerType trigger, IScriptContainer container, IScrip
this.gas_amount = gas_free + gas.GetData();
this.testMode = testMode;
this.Trigger = trigger;
if( table is CachedScriptTable)
{
this.script_table = (CachedScriptTable)table;
}
}

private bool CheckArraySize(OpCode nextInstruction)
Expand Down Expand Up @@ -229,6 +235,23 @@ private bool CheckStackSize(OpCode nextInstruction)
return true;
}

private bool CheckDynamicInvoke(OpCode nextInstruction)
{
if(nextInstruction == OpCode.APPCALL || nextInstruction == OpCode.TAILCALL)
{
for (int i = CurrentContext.InstructionPointer + 1; i < CurrentContext.InstructionPointer + 21; i++)
{
if (CurrentContext.Script[i] != 0) return true;
}
// if we get this far it is a dynamic call
// now look at the current executing script
// to determine if it can do dynamic calls
ContractState contract = script_table.GetContractState(CurrentContext.ScriptHash);
return contract.HasDynamicInvoke;
}
return true;
}

public new bool Execute()
{
try
Expand All @@ -247,6 +270,7 @@ private bool CheckStackSize(OpCode nextInstruction)
if (!CheckArraySize(nextOpcode)) return false;
if (!CheckInvocationStack(nextOpcode)) return false;
if (!CheckBigIntegers(nextOpcode)) return false;
if (!CheckDynamicInvoke(nextOpcode)) return false;
}

StepInto();
Expand Down Expand Up @@ -343,7 +367,19 @@ protected virtual long GetPriceForSysCall()
case "Neo.Contract.Migrate":
case "AntShares.Contract.Create":
case "AntShares.Contract.Migrate":
return 500L * 100000000L / ratio;
long fee = 100L;

ContractPropertyState contract_properties = (ContractPropertyState)(byte)EvaluationStack.Peek(3).GetBigInteger();

if(contract_properties.HasFlag(ContractPropertyState.HasStorage))
{
fee += 400L;
}
if(contract_properties.HasFlag(ContractPropertyState.HasDynamicInvoke))
{
fee += 500L;
}
return fee * 100000000L / ratio;
case "Neo.Storage.Get":
case "AntShares.Storage.Get":
return 100;
Expand Down
5 changes: 5 additions & 0 deletions neo/SmartContract/CachedScriptTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,10 @@ byte[] IScriptTable.GetScript(byte[] script_hash)
{
return contracts[new UInt160(script_hash)].Script;
}

public ContractState GetContractState(byte[] script_hash)
{
return contracts[new UInt160(script_hash)];
}
}
}
10 changes: 5 additions & 5 deletions neo/SmartContract/StateMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ private bool Contract_Create(ExecutionEngine engine)
ContractParameterType[] parameter_list = engine.EvaluationStack.Pop().GetByteArray().Select(p => (ContractParameterType)p).ToArray();
if (parameter_list.Length > 252) return false;
ContractParameterType return_type = (ContractParameterType)(byte)engine.EvaluationStack.Pop().GetBigInteger();
bool need_storage = engine.EvaluationStack.Pop().GetBoolean();
ContractPropertyState contract_properties = (ContractPropertyState)(byte)engine.EvaluationStack.Pop().GetBigInteger();
if (engine.EvaluationStack.Peek().GetByteArray().Length > 252) return false;
string name = Encoding.UTF8.GetString(engine.EvaluationStack.Pop().GetByteArray());
if (engine.EvaluationStack.Peek().GetByteArray().Length > 252) return false;
Expand All @@ -221,7 +221,7 @@ private bool Contract_Create(ExecutionEngine engine)
Script = script,
ParameterList = parameter_list,
ReturnType = return_type,
HasStorage = need_storage,
ContractProperties = contract_properties,
Name = name,
CodeVersion = version,
Author = author,
Expand All @@ -242,7 +242,7 @@ private bool Contract_Migrate(ExecutionEngine engine)
ContractParameterType[] parameter_list = engine.EvaluationStack.Pop().GetByteArray().Select(p => (ContractParameterType)p).ToArray();
if (parameter_list.Length > 252) return false;
ContractParameterType return_type = (ContractParameterType)(byte)engine.EvaluationStack.Pop().GetBigInteger();
bool need_storage = engine.EvaluationStack.Pop().GetBoolean();
ContractPropertyState contract_properties = (ContractPropertyState)(byte)engine.EvaluationStack.Pop().GetBigInteger();
if (engine.EvaluationStack.Peek().GetByteArray().Length > 252) return false;
string name = Encoding.UTF8.GetString(engine.EvaluationStack.Pop().GetByteArray());
if (engine.EvaluationStack.Peek().GetByteArray().Length > 252) return false;
Expand All @@ -262,7 +262,7 @@ private bool Contract_Migrate(ExecutionEngine engine)
Script = script,
ParameterList = parameter_list,
ReturnType = return_type,
HasStorage = need_storage,
ContractProperties = contract_properties,
Name = name,
CodeVersion = version,
Author = author,
Expand All @@ -271,7 +271,7 @@ private bool Contract_Migrate(ExecutionEngine engine)
};
contracts.Add(hash, contract);
contracts_created.Add(hash, new UInt160(engine.CurrentContext.ScriptHash));
if (need_storage)
if (contract.HasStorage)
{
foreach (var pair in storages.Find(engine.CurrentContext.ScriptHash).ToArray())
{
Expand Down