乐趣区

NEO改进协议提案4(NEP-4)

文章目录

摘要
动机
详述 neoneo-vmneo 编译器智能合约示例
原理
向后兼容性
实现

摘要
此 NEP 提案概述了一种机制,通过该机制,智能合约能够调用直到运行时才知道的其他智能合约,而不仅限于调用在编译时定义的智能合约。为了保持智能合约与未来动态分片过程接口的能力,包括一份用于构建智能合约的提案详述会表示智能合约是否需要动态合约调用功能。
动机
此 NEP 的动机是为让智能合约(SC)的的作者能够为编译时不可知的 SC 提供接口。例如,操作 NEP-5 token 的分散交换的 SC 可以调用在运行时才确定的 token 的 SC 的 transferFrom 方法。目前,这样的 SC 需要对所有支持的 NEP-5 token 地址进行硬编码,并在添加新 token 时重新发布。以太坊上的许多 SC 都需要此功能,包括任何符合 ERC223 token 标准的功能。通过让 SC 作者能够在运行时指定 SC 与之交互,类似于更先进的以太坊合约中包含的功能将更容易开发和维护。值得注意的是,向 NEO 添加动态 SC 调用会影响可伸缩性。通过动态 SC 调用,我们不用再事先知道将调用哪些其他 SC,因此 VM 状态的子集必须可用于执行才能成功。这使得动态分片更难实现。为了克服可扩展性的缺点,该提议在区块链上创建时为每个 SC 添加一个设定,以表示它是否需要动态调用功能。该设定将允许所有现存的合约和大多数未来合约在预先已知的存储上下文中执行,因此更适合于动态分片,同时还使 SC 更强大和更具表现力。考虑到动态调用功能的可扩展性缺陷,该 NEP 建议了一个需要此功能的 SC 的更新费用结构。下面列出了更新费用结构的样例实现。
详述
该提案概述了 Neo 项目的三个部分的变更,并提供了如何在 SC 中使用此变更的示例:•neo•neo-vm•neo 编译器•智能合约实例下面列出的变更并非试图详尽无遗,而是概述每个库中所需的重要变更。
neo 为了让一份 SC 表示其是否能够动态调用其他 SC,该 NEP 建议在 neo.Core.ContractState 对象中添加以下属性,且默认值为 false
public bool HasDynamicInvoke
HasDynamicInvoke 属性为了使实现与当前的 Neo 协议保持互操作,HasDynamicInvoke 属性将被序列化为字节标志跟在现有的 HasStorage 属性之后:
[Flags]
public enum ContractPropertyState : byte
{
NoProperty = 0,
HasStorage = 1 << 0,
HasDynamicInvoke = 1 << 1,
}

public class ContractState : StateBase, ICloneable<ContractState>
{

public ContractPropertyState ContractProperties;

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

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

public override void Serialize(BinaryWriter writer)
{
base.Serialize(writer);
writer.WriteVarBytes(Script);
writer.WriteVarBytes(ParameterList.Cast<byte>().ToArray());
writer.Write((byte)ReturnType);
writer.Write(ContractProperties); // currently is writer.Write(HasStorage)
writer.WriteVarString(Name);
writer.WriteVarString(CodeVersion);
writer.WriteVarString(Author);
writer.WriteVarString(Email);
writer.WriteVarString(Description);
}

以下在 neo.SmartContract.ApplicationEngine 中的变更用于计量合约创建不同的 Gas 费用。没有额外附加功能的合约创建费用会被降低,而那些 HasDynamicInvoke 或 HasStorage 属性为 true 的合约创建会产生额外的费用。
protected virtual long GetPriceForSysCall()
{
// lines omitted

case “Neo.Contract.Create”:
case “Neo.Contract.Migrate”:
case “AntShares.Contract.Create”:
case “AntShares.Contract.Migrate”:

long fee = 100L;
ContractState contract = PeekContractState() // this would need to be implemented

if(contract.HasStorage)
{
fee += 400L
}

if(contract.HasDynamicInvoke)
{
fee += 500L;
}

return fee * 100000000L / ratio;

neo-vm 本详细提案给 NEO 虚拟机添加了一个新 OpCode,代表相对于静态的动态 AppCall 的使用 DYNAMICCALL = 0xFADYNAMICCALL OpCode 在 neo.VM.ExecutionEngine.ExecuteOp 方法的执行也按照以下方式不同于现有的 APPCALL 和 TAILCALL OpCodes
case OpCode.APPCALL:
case OpCode.TAILCALL:
case OpCode.DYNAMICCALL:
{
if (table == null)
{
State |= VMState.FAULT;
return;
}

byte[] script_hash = null;

if (opcode == OpCode.DYNAMICCALL)
{

script_hash = EvaluationStack.Pop().GetByteArray();

if (script_hash.Length != 20)
{
State |= VMState.FAULT
return;
}

} else {

script_hash = context.OpReader.ReadBytes(20);
}

byte[] script = table.GetScript(script_hash);
if (script == null)
{
State |= VMState.FAULT;
return;
}
if (opcode == OpCode.TAILCALL || opcode == OpCode.DYNAMICCALL)
InvocationStack.Pop().Dispose();
LoadScript(script);
}
break;
neo 编译器将方法调用转换为 DYNAMICCALL 的示例方法如下:
else if (calltype == CallType.DYNAMICCALL)
{
_ConvertPush(callhash, null, to)
_Convert1by1(VM.OpCode.DYNAMICCALL, null, to);

}

智能合约示例以下是一个 SC 演示了所提案功能的简单使用
using Neo.SmartContract.Framework.Services.Neo;

namespace Neo.SmartContract
{
public class DynamicTotalSupply : Framework.SmartContract
{
public static int Main(byte[] contract_hash)
{

if(contract_hash.Length == 20) {

BigInteger totalSupply = DynamicCall(contract_hash, ‘totalSupply’)

return totalSupply;
}

return 0;
}
}
}
原理
用动态 SC 调用来动态分片(以太坊已经提出了许多解决方案)并不是不可能的,尽管这会增添已经很困难的任务。仅仅因为我们事先知道计算调用图并不意味着我们能够成功地完美分配资源,没有重叠的子集。仍然可能需要实现分片之间的通信,如以太坊提案中那样。考虑到这一点,不向 SC 添加任何关于是否需要动态调用的元数据并实现动态应用程序调用是有可能的,因为它们可以以相同的方式执行和延申。但是,即使在可以实现一个系统可以动态 SC 调用和动态分片这种情况下,本提案仍认为存储 HasDynamicInvoke 属性在该实现中可能是很有用的。存储此属性还能使系统对使用 HasDynamicInvoke 属性发布的 SC 收取不同的费用。
向后兼容性
本 NEP 介绍了一套不影响现有 SC 的新功能。通过利用现有字节来指示 SC 是否需要存储区或添加额外标记,我们能够在不影响现有网络协议的情况下维持现有功能和添加该新功能。
实现
• neo-project/neo: https://github.com/neo-projec…• neo-project/neo-vm: https://github.com/neo-projec…
原文链接:https://github.com/neo-projec…

退出移动版