Skip to content

Latest commit

 

History

History
 
 

合约

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

智能合约

NEO3变更部分

NEO3中所有交易都是智能合约的调用,除了一些互操作指令和OpCode的调整,NEO3中比较大的特性包括:

  • 新增

    • Manifest文件:用于描述合约的特征,随avm文件一起部署到Neo区块链。
    • 原生合约:不通过虚拟机执行,而直接运行在Neo原生代码中,目前包括:NeoToken,GasToken,以及PolicyContract。
    • 网络资源访问: 待补充。
    • system 触发器:用于节点收到新区块后,触发原生合约的执行。
    • 互操作服务接口:System.Blockchain.GetTransactionFromBlock
  • 更新

    • 降低了合约执行互操作接口所对应的系统费用
  • 删除

    • 互操作服务接口:Neo.Header.GetVersion, Neo.Header.GetMerkleRoot, Neo.Header.GetNextConsensus, Neo.Transaction.GetScript, Neo.Transaction.GetWitnesses, Neo.Witness.GetVerificationScript, Neo.Contract.GetScript, Neo.Contract.IsPayable, System.Blockchain.GetHeader, System.Header.GetIndex, System.Header.GetHash, System.Header.GetPrevHash, System.Header.GetTimestamp, System.Block.GetTransactionCount, System.Block.GetTransactions, System.Block.GetTransaction, System.Transaction.GetHash

Manifest

NEO3 变更: 新添加了Manifest文件,随avm文件一起部署到Neo区块链

现在每个合约都需要对应的manifest文件描述其属性,其内容包括:Groups, Features, ABI,Permissions, Trusts, SafeMethods。

一个manifest内容示例如下:

{
    "groups": [
        {
            "pubKey": "",
            "signature": ""
        }
    ],
    "features": {
        "storage": false,
        "payable": false
    },
    "abi": {
      "hash": "0x562851057d8afbc08fabc8c438d7cc771aef2195",
      "entrypoint": {
        "name": "main",
        "parameters": [
          {
            "name": "operation",
            "type": "String"
          },
          {
            "name": "args",
            "type": "Array"
          }
        ],
        "returntype": "Any"
      },
      "methods": [
        {
          "name": "name",
          "parameters": [],
          "returntype": "string"
        }
      ],
      "events": [
        {
          "name": "transfered",
          "parameters": [
            {"name": "from","type": "Hash160"},
            {"name": "to","type": "Hash160"},
            {"name": "value","type": "Integer"}
          ]
        }
      ]
    },
    "permissions": [
        {
            "contract": "*",
            "methods": "*"
        }
    ],
    "trusts": "*",
    "safemethods": "*"
}
  • Groups:声明本合约所归属的组,可以支持多个, 每一个组由一个公钥和签名表示。
  • Features:声明智能合约的特性。其中属性值storage表明合约可以访问存储区, payable表明合约可以接受资产的转入。
  • ABI:声明智能合约的接口信息,可以参考NEP-3。接口的基础属性包括:
    • Hash: 16进制编码的合约脚本哈希;
    • EntryPoint: 提供了合约入口方法的详细信息,包括方法名、方法参数以及方法返回值;
    • Methods: 由合约方法的详细信息构成的数组;
    • Events: 由合约事件构成的数组。基于 ABI 信息,可实现合约间的相互调用。
  • Permissions:声明合约可调用的其他合约和方法。执行合约调用时,会检查Permission中配置的权限,若没有相应权限,则调用操作会执行失败。
  • Trusts:声明合约可以被哪些合约或者哪些合约组安全地调用。
  • SafeMethods:声明哪些方法是SafeMethod,SafeMethod通常是不会修改存储区,只读取区块链数据的方法,被调用时不会给用户接口返回警告信息。

触发器

触发器可以使合约根据不同的使用场景执行不同的逻辑。

NEO3 变更: 新添加System触发器

  • System 触发器

    此触发器为NEO3新增触发器类型,仅用于NEO3新添加的原始合约中,即NEO和GAS。当节点收到新区块后触发,目前只会触发原生合约的执行。当节点收到新区块,持久化之前会调用所有原生合约的onPersist方法,只有触发方式为System才会继续执行。

    该触发器不对普通合约的执行造成任何影响。

  • Application 触发器

    应用触发器的目的在于将该合约作为应用函数进行调用,应用函数可以接受多个参数,对区块链的状态进行更改,并返回任意类型的返回值。以下是一个简单的C#智能合约:

    public static Object Main(string operation, params object[] args)
    {
      if (Runtime.Trigger == TriggerType.Application)
      {
          if (operation == "FunctionA") return FunctionA(args);
      }  
    }
    public static bool FunctionA(params object[] args)
    {
      //some code  
    }

    NEO3中所有交易都为合约的调用,当一笔交易被广播和确认后,智能合约由共识节点执行,普通节点在转发交易时不执行智能合约。智能合约执行成功不代表交易的成功,而交易的成功也不决定智能合约执行的成功。

  • Verification 触发器

    验证触发器的目的在于将该合约作为验证函数进行调用,验证函数可以接受多个参数,并且应返回有效的布尔值,标志着交易或区块的有效性。

    当你想从 A 账户向 B 账户进行转账时,会触发验证合约,所有收到这笔交易的节点(包括普通节点和共识节点)都会验证 A 账户的合约,如果返回值为 true,即转账成功。如果返回 false,即转账失败。

    如果鉴权合约执行失败,这笔交易将不会被写入区块链中。

    下面的代码就是一个验证合约的简单示例,当条件 A 满足时,返回 true,即转账成功。否则返回 false,转账失败。

    using Neo.SmartContract.Framework;
    using Neo.SmartContract.Framework.Neo;
    
    public static bool Main(byte[] signature)
    {
        if (/*条件A*/)
            return true;
        else
            return false;
    }

    下面的这段代码的作用与上面的基本相同,但对运行时的触发器进行了判断,仅当触发器为验证触发器时执行验证部分的代码,这在复杂的智能合约中很有用,如果一个智能合约实现了多种触发器,应该在 Main 方法中对触发器进行判断。

    using Neo.SmartContract.Framework;
    using Neo.SmartContract.Framework.Neo;
    
    public static bool Main(byte[] signature)
    {
        if (Runtime.Trigger == TriggerType.Verification)
        {
            if (/*条件A*/)
                    return true;
                else
                    return false;
        }  
    }

原生合约

介绍

原生合约是直接在原生代码中执行,而不是在虚拟机中运行的合约。原生合约公开其服务名称,供其他合约调用。目前已有的原生合约包括NeoToken,GasToken,PolicyToken。

NeoToken

简称 NEO,是Neo的治理代币,用于执行对 Neo 网络的管理权,符合 NEP-5 标准。NEO 的总量为 1 亿,最小单位为 1,且不可分割。Neo 在创世块中注册生成。具体接口细节如下:

标*的方法为NEP-5标准接口

  • name*: Token的名称

    参数列表 无参数
    返回值 返回值类型 描述
    String Token的名称
    费用(GAS) 0.00
    在合约中调用示例
    using Neo.SmartContract.Framework;
    using Neo.SmartContract.Framework.System;
    
    public static object Main(string method, object[] args)
    {
      private static string neoScriptHash = "0x43cf98eddbe047e198a3e5d57006311442a0ca15";
        if (Runtime.Trigger == TriggerType.Application)
        {
            if (method == "neoName") {
              string name = Contract.Call(neoScriptHash.HexToBytes(), "name", new object[]{});
              return name;
            }
        }  
    }

    拼接脚本示例

    通过System.Contract.Call来调用合约脚本为:

    PUSH0
    NEWARRAY
    PUSHBYTES4  6e616d65
    PUSHBYTES20 0x43cf98eddbe047e198a3e5d57006311442a0ca15
    SYSCALL     0x627d5b52
    

    生成脚本的C#代码为:

    ScriptBuilder sb = new ScriptBuilder()
    UInt160 scriptHash = UInt160.Parse("0x43cf98eddbe047e198a3e5d57006311442a0ca15");
    sb.EmitPush(0);
    sb.Emit(OpCode.NEWARRAY);
    sb.EmitPush("name");
    sb.EmitPush(scriptHash);
    sb.EmitSysCall(InteropService.System_Contract_Call);
    byte[] script = sb.ToArray();
    
  • symbol*:Token的简称

    参数列表 无参数
    返回值 返回值类型 描述
    String Token的简称
    费用(GAS) 0.00
  • decimals*: Token的计算精度

    参数列表 无参数
    返回值 返回值类型 描述
    Unit Token的计算精度
    费用(GAS) 0.00
  • totalSupply*: 总发行量

    参数列表 无参数
    返回值 返回值类型 描述
    BigInteger Token的总发行量
    费用(GAS) 0.01
  • balanceOf*: 指定地址的Token余额

    参数列表 参数名称 参数类型 描述
    account Hash160 要查询账户的ScriptHash
    返回值 返回值类型 描述
    BigInteger 余额数值
    费用(GAS) 0.01
  • transfer*: 转账

    参数列表 参数名称 参数类型 描述
    from Hash160 转出账户的ScriptHash
    to Hash160 转入账户的ScriptHash
    amount Integer 转账的Token数量
    返回值 返回值类型 描述
    Boolean 转账结果,true:成功,false:失败
    费用(GAS) 0.08
    在合约中调用示例
    using Neo.SmartContract.Framework;
    using Neo.SmartContract.Framework.System;
    
    public static object Main(string method, object[] args)
    {
      private static string neoScriptHash = "0x43cf98eddbe047e198a3e5d57006311442a0ca15";
        if (Runtime.Trigger == TriggerType.Application)
        {
            if (method == "transferNeo") {
              byte[] from  = "AesUJTLg93cWMTSzp2snxpBJSCets89ebM".ToScriptHash();
              byte[] to    = "AMhbbwR8r6LuTx5okkZudvvp3LW6Fh1Y7o".ToScriptHash();
              BigInterger value = new BigInteger(100000000);
              bool result = Contract.Call(neoScriptHash.HexToBytes(), "transfer", new Object[]{from, to, value.AsByteArray()});
              return result;
            }
        }  
    }

    拼接脚本示例

    通过System.Contract.Call来调用合约脚本为:

    PUSHBYTE4   00e1f505
    PUSHBYTE20  4101b2a928fd88e1d976fd23c2db25a822338a08
    PUSHBYTE20  fd59e6a0e3eee5cd9cea7233f01e1cc9c8b23502
    PUSH3
    PACK
    PUSHBYTES4  7472616e73666572
    PUSHBYTES20 0x43cf98eddbe047e198a3e5d57006311442a0ca15
    SYSCALL     0x627d5b52
    

    生成脚本的C#代码为:

    ScriptBuilder sb = new ScriptBuilder()
    UInt160 scriptHash = UInt160.Parse("0x43cf98eddbe047e198a3e5d57006311442a0ca15");
    UInt160 from = UInt160.Parse("0xfd59e6a0e3eee5cd9cea7233f01e1cc9c8b23502");
    UInt160 to = UInt160.Parse("0x4101b2a928fd88e1d976fd23c2db25a822338a08");
    long value = 1000000000;
    sb.EmitPush(value);
    sb.EmitPush(to);
    sb.EmitPush(from);
    sb.Emit(OpCode.PUSH3);
    sb.Emit(OpCode.PACK);
    sb.EmitPush("transfer");
    sb.EmitPush(scriptHash);
    sb.EmitSysCall(InteropService.System_Contract_Call);
    byte[] script = sb.ToArray();
    
  • unClaimGas:获取到指定高度,未claim的GAS数量

    参数列表 参数名称 参数类型 描述
    account Hash160 要查询账户的ScriptHash
    end Integer 要查询的截止高度
    返回值 返回值类型 描述
    integer 未claimGAS数量
    费用(GAS) 0.03
    在合约中调用示例
    using Neo.SmartContract.Framework;
    using Neo.SmartContract.Framework.System;
    
    public static object Main(string method, object[] args)
    {
      private static string neoScriptHash = "0x43cf98eddbe047e198a3e5d57006311442a0ca15";
        if (Runtime.Trigger == TriggerType.Application)
        {
            if (method == "accountUnClaimGas") {
              byte[] account = "AXx1A21wcoXuVxxxggkQChxQP5EGYe6zsN".ToScriptHash();
              int height = 1000000;
              int gas = Contract.Call(neoScriptHash.HexToBytes(), "unClaimGas", new Object[]{account, height});
              return gas;
            }
        }  
    }

    拼接脚本示例

    通过System.Contract.Call来调用合约脚本为:

    PUSHBYTE3   40420f
    PUSHBYTE20  b16c70b94928ddb62f5793fbc98d6245ee308ecd
    PUSH2
    PACK
    PUSHBYTES4  756e436c61696d476173
    PUSHBYTES20 0x43cf98eddbe047e198a3e5d57006311442a0ca15
    SYSCALL     0x627d5b52
    

    生成脚本的C#代码为:

    ScriptBuilder sb = new ScriptBuilder()
    UInt160 scriptHash = UInt160.Parse("0x43cf98eddbe047e198a3e5d57006311442a0ca15");
    UInt160 account = UInt160.Parse("0xb16c70b94928ddb62f5793fbc98d6245ee308ecd");
    int height = 1000000
    sb.EmitPush(height);
    sb.EmitPush(account);
    sb.Emit(OpCode.PUSH2);
    sb.Emit(OpCode.PACK);
    sb.EmitPush("unClaimGas");
    sb.EmitPush(scriptHash);
    sb.EmitSysCall(InteropService.System_Contract_Call);
    byte[] script = sb.ToArray();
    
  • RegisterValidator:注册验证人

    参数列表 参数名称 参数类型 描述
    pubKey PublicKey 要注册验证人的账户的公钥
    返回值 返回值类型 描述
    Boolean 注册结果,true:成功, false:失败
    费用(GAS) 0.05
  • getRegisteredValidators:获取当前注册的验证人和备选节点信息

    参数列表 无参数
    返回值 返回值类型 描述
    Array 所有验证人和备选节点信息
    费用(GAS) 1.00
  • getValidators: 获取当前区块所有验证人信息

    参数列表 无参数
    返回值 返回值类型 描述
    Array 所有验证人信息
    费用(GAS) 1.00
  • getNextBlockValidators: 获取下一个区块的验证人信息

    参数列表 无参数
    返回值 返回值类型 描述
    Array 所有验证人信息
    费用(GAS) 1.00
  • vote:投票选举验证人

    参数列表 参数名称 参数类型 描述
    account Hash160 投票人的ScriptHash
    pubkeys Array 投给验证人的公钥
    返回值 返回值类型 描述
    Boolean 投票结果,true:成功, false:失败
    费用(GAS) 5.00

GasToken

简称 GAS,Neo 的燃料代币,用于支付手续费,符合 NEP-5 标准。Neo 网络上的 交易费用和共识节点激励均以 GAS 来支付。GAS 总量 1 亿,最小单位 0.00000001。 GAS 在创始块中被注册,但未分发。
GAS 的分发机制: 生成一个新区块时会伴随产生新的 GAS,所生成的 GAS 和系统 费会分发给 NEO 的持有者。用户地址中的 NEO 余额发生变化时会自动进行 GAS 的计 算和分发,计算方法如下图所示:

GAS distribution

其中,m 表示用户上一次提取 GAS 时所处的区块高度,n 为当前的区块高度,NEO 表示 m 至 n 期间用户持有的 NEO 的数量。BlockBonus 代表每个区块可以提取的 GAS 量,具体细节可参看经济模型部分。SystemFee 代表该区块中所有交易的系统费之和。GasToken的详细接口介绍如下:

标*的方法为NEP-5标准接口

  • name: Token的名称

    参数列表 无参数
    返回值 返回值类型 描述
    String Token的名称
    费用(GAS) 0.00
  • symbol: Token的简称

    参数列表 无参数
    返回值 返回值类型 描述
    String Token的简称
    费用(GAS) 0.00
  • decimals: Token的计算精度

    参数列表 无参数
    返回值 返回值类型 描述
    Unit Token的计算精度
    费用(GAS) 0.00
  • totalSupply: 总发行量

    参数列表 无参数
    返回值 返回值类型 描述
    BigInteger Token的总发行量
    费用(GAS) 0.01
  • balanceOf: 指定地址的Token余额

    参数列表 参数名称 参数类型 描述
    account Hash160 要查询账户的ScriptHash
    返回值 返回值类型 描述
    Integer 余额数值
    费用(GAS) 0.01
  • transfer: 转账

    参数列表 参数名称 参数类型 描述
    from Hash160 转出账户的ScriptHash
    to Hash160 转入账户的ScriptHash
    amount Integer 转账的Token数量
    返回值 返回值类型 描述
    Boolean 转账结果,true:成功,false:失败
    费用(GAS) 0.08
  • getSysFeeAmount: 获取截止到某一高度的系统费总和

    参数列表 参数名称 参数类型 描述
    index Integer 要查询的高度
    返回值 返回值类型 描述
    Integer 系统费总值
    费用(GAS) 0.01

PolicyContract

配置共识策略的合约,保存了共识过程中相关参数,例如区块最大交易数,每字节手续费等。接口详细介绍如下:

  • getMaxTransactionPerBlock: 获取每个区块最大交易数

    参数列表 无参数
    返回值 返回值类型 描述
    Integer 区块最大交易数
    费用(GAS) 0.01
  • GetFeePerByte: 获取每个区块最大交易数

    参数列表 无参数
    返回值 返回值类型 描述
    Integer 每字节手续费
    费用(GAS) 0.01
  • getBlockedAccounts: 获取被加入黑名单的地址列表

    参数列表 无参数
    返回值 返回值类型 描述
    Array 黑名单列表
    费用(GAS) 0.01
  • setMaxTransactionsPerBlock: 设置每个区块的最大交易数

    参数列表 参数名称 参数类型 描述
    value Integer 要设置的数值
    返回值 返回值类型 描述
    Boolean 结果,true:设置成功, false:设置失败
    费用(GAS) 0.03
  • setFeePerByte:设置每比特手续费

    参数列表 参数名称 参数类型 描述
    value Integer 要设置的数值
    返回值 返回值类型 描述
    Boolean 结果,true:设置成功,false:设置失败
    费用(GAS) 0.03
  • blockAccount:将某个地址加入黑名单

    参数列表 参数名称 参数类型 描述
    account Hash160 要列入黑名单的地址
    返回值 返回值类型 描述
    Boolean 结果,true:设置成功,false:设置失败
    费用(GAS) 0.03
  • unblockAccount:将某个地址从黑名单移除

    参数列表 参数名称 参数类型 描述
    account Hash160 要移出黑名单的地址
    返回值 返回值类型 描述
    Boolean true:设置成功,false:设置失败
    费用(GAS) 0.03

更多原生合约,敬请期待

互操作服务

互操作服务层提供了智能合约所能访问区块链数据的一些 API,利用这些 API,可以访问区块信息、交易信息、合约信息、资产信息等。除此之外互操作服务层还为每个合约提供了一个持久化存储区的功能。Neo 的每个智能合约在创建的时候都可选地启用一个私有存储区,存储区是 key-value 形式的,Neo 智能合约由合约的被调用者决定持久化存储区的上下文,而非调用者来决定。当然,调用者需要将自己的存储上下文传给被调用者(即完成授权)后,被调用者才可以执行读写操作。互操作服务分为System部分和Neo部分。

互操作服务原理

Neo程序启动时会将一系列的互操作接口注册到虚拟机,供智能合约调用。

  • 服务名称:每个互操作都有一个名称,例如 System.Contract.Call
  • 映射方法:每个互操作服务都有对应的原生方法,例如private static bool Contract_Call(ApplicationEngine engine),其为在客户端中实际调用的方法
  • 系统费:每个互操作服务都有其系统费计算方法或者固定系统费。
  • 触发方式:每个互操作接口都有支持的触发方式,比如TriggerType.All支持所有触发器

注册时就是Neo客户端将互操作接口的服务名称,映射的具体方法,系统费计算方法,支持的触发方式封装为一个InteropDescriptor存储在Dictionary中,索引为互操作接口名称的哈希值,其计算方法为: BitConverter.ToUInt32(Encoding.ASCII.GetBytes(ServiceName).Sha256(), 0)

例如,System.Contract.Call的哈希值为0x627d5b52

互操作服务使用

  • 智能合约: 智能合约中使用的互操作接口由对应的智能合约开发框架提供,直接调用即可,当编译时会由编译器编译成可在NeoVM中执行的操作符指令
  • 交易Script: 很多时候需要手动拼接执行脚本,这时候使用互操作服务的接口名称的哈希值与SYSCALL操作符来实现。

例如,如果要通过System.Contract.Call来调用合约0x43cf98eddbe047e198a3e5d57006311442a0ca15name方法:

PUSH0
NEWARRAY
PUSHBYTES4  6e616d65
PUSHBYTES20 0x43cf98eddbe047e198a3e5d57006311442a0ca15
SYSCALL     0x627d5b52

C#代码为:

ScriptBuilder sb = new ScriptBuilder()
UInt160 scriptHash = UInt160.Parse("0x43cf98eddbe047e198a3e5d57006311442a0ca15");
sb.EmitPush(0);
sb.Emit(OpCode.NEWARRAY);
sb.EmitPush("name");
sb.EmitPush(scriptHash);
sb.EmitSysCall(InteropService.System_Contract_Call); //根据互操作索引调用
byte[] script = sb.ToArray();

例如在C#中可以如下方式调用:

using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Neo;

namespace MyContract
{
  public class MyContract: SmartContract
  {
    public static readonly byte[] GAS = HexToBytes("0xa1760976db5fcdfab2a9930e8f6ce875b2d18225");
    public static object main(string method, object[] args)
    {
      if (method == "transferGAS") {
        if (args.Length < 3) return false;
        return Contract.Call(GAS, "Transfer", args);
      }
    }
  }
}

互操作服务分为System部分和Neo部分,具体接口介绍如下:

System部分

System.ExecutionEngine.GetScriptContainer

功能描述 获取该智能合约的脚本容器
C#函数 byte[] GetScriptContainer()

System.ExecutionEngine.GetExecutingScriptHash

功能描述 获取正在执行的智能合约的脚本哈希
C#函数 byte[] GetExecutingScriptHash()

System.ExecutionEngine.GetCallingScriptHash

功能描述 获取智能合约调用者的脚本哈希
C#函数 byte[] GetExecutingScriptHash()

System.ExecutionEngine.GetEntryScriptHash

功能描述 获得该智能合约的入口点(合约调用链的起点)的脚本散列
C#函数 byte[] GetEntryScriptHash()

System.Runtime.Platform

功能描述 获取当前执行智能合约的平台信息
C#函数 string Platform()

System.Runtime.GetTrigger

功能描述 获取该智能合约的触发条件
C#函数 TriggerType Trigger()

System.Runtime.CheckWitness

功能描述 验证调用该合约的容器是否被指定账户脚本哈希签名
C#函数 bool CheckWitness(byte[] hashOrPubKey)

System.Runtime.Notify

功能描述 向执行智能合约的程序发送通知
C#函数 bool Notify(params object[] state)

System.Runtime.Log

功能描述 向执行智能合约的程序发送通知
C#函数 void Log(string message)

System.Runtime.GetTime

功能描述 获取当前区块的时间戳
C#函数 uint Time

System.Runtime.Serialize

功能描述 序列化
C#函数 object Deserialize(this byte[] source)

System.Runtime.Deserialize

功能描述 反系列化
C#函数 byte[] Serialize(this object source)

System.Runtime.GetInvocationCounter

功能描述 获取当前合约的调用次数
C#函数 int GetInvocationCounter()

System.Runtime.GetNotifications

Description 获取某合约执行的所有通知
C# 函数 StackItem[][] GetNotifications(Hash160 scriptHash)

System.Crypto.Verify

功能描述 使用公钥验证消息的签名
C#函数 bool Verify(object message, byte[] signature, byte[] pubKey)

System.Blockchain.GetHeight

功能描述 获取当前区块的高度
C#函数 uint GetHeight()

System.Blockchain.GetBlock

功能描述 根据区块哈希或者区块高度获取区块
C#函数 Block GetBlock(uint height)
Block GetBlock(byte[] hash)

System.Blockchain.GetTransaction

功能描述 根据交易ID获取交易
C#函数 Transaction GetTransaction(byte[] hash)

System.Blockchain.GetTransactionHeight

功能描述 根据交易ID获取交易所在的区块高度
C#函数 int GetTransactionHeight(byte[] hash)

System.Blockchain.GetTransactionFromBlock

功能描述 根据区块中交易ID获取交易
C#函数 Transaction GetTransaction(byte[] hash)

System.Blockchain.GetContract

功能描述 根据合约哈希获取合约
C#函数 Contract GetContract(byte[] scriptHash)

System.Contract.Call

功能描述 调用合约
C#函数 void Call(byte[] scriptHash, string method, object[] args)
void Call(Contract contract, string method, object[] args)

System.Contract.Destroy

功能描述 销毁当前合约
C#函数 void Destroy()

System.Storage.GetContext

功能描述 获取当前合约存储去的上下文
C#函数 StorageContext GetContext()
说明 StorageContext中的IsReadOnly为false

System.Storage.GetReadOnlyContext

功能描述 以只读方式获取当前合约存储去的上下文
C#函数 StorageContext GetContext()
说明 StorageContext中的IsReadOnly为true

System.Storage.Get

功能描述 根据Key值,从存储区获取对应的Value
C#函数 byte[] Get(StorageContext context, byte[] key)

System.Storage.Put

功能描述 根据存储上下文,向存储区写入Key-Value
C#函数 byte[] Get(StorageContext context, byte[] key, byte[] value)

System.Storage.PutEx

功能描述 根据存储上下文,依据flag,向存储区写入Key-Value
C#函数 byte[] Get(StorageContext context, byte[] key, byte[] value, StorageFlags flags)
说明 StorageFlags表明了写入数据的属性,默认None,
数据可以被读写。如果是Constant,数据被写入存储区后不能被修改也不能被删除

System.Storage.Delete

功能描述 根据Key值,从存储区删除存储的Key-Value数据
C#函数 void Delete(StorageContext context, byte[] key)
说明 如果数据的StorageFlags包含Constant,不能被删除

System.StorageContext.AsReadOnly

功能描述 将当前上下文修改为只读模式
C#函数 void AsReadOnly(this StorageContext context)
说明 将StorageContext中的IsReadOnly设置为true

Neo部分

Neo.Native.Deploy

功能描述 部署并初始化所有原生合约
说明 只能在创世区块调用

Neo.Crypto.CheckSig

功能描述 根据公钥,验证当前脚本容器的签名
C#函数 bool CheckSig(byte[] signature, byte[] pubKey)

Neo.Crypto.CheckMultiSig

功能描述 根据公钥,验证当前脚本容器的签名
C#函数 bool CheckMultiSig(byte[][] signatures, byte[][] pubKeys)

Neo.Account.IsStandard

功能描述 判断是否是标准账户
C#函数 bool IsStandard(byte[] scriptHash)

Neo.Contract.Create

功能描述 部署合约
C#函数 Contract Create(byte[] script, string manifest)
说明 script合约内容不能超过1MB,manifest内容不能超过2KB

Neo.Contract.Update

功能描述 升级合约
C#函数 Contract Create(byte[] script, string manifest)
说明 script合约内容不能超过1MB,不能是已经部署的合约;manifest内容不能超过2KB;
升级后旧合约会被摧毁

Neo.Storage.Find

功能描述 在当前存储上下文中存储区寻找指定前缀内容
C#函数 Iterator < byte[], byte[] > Find(StorageContext context, byte[] prefix)

Neo.Enumerator.Create

功能描述 创建一个枚举器
C#函数 Enumerator Create(object[] array)

Neo.Enumerator.Next

功能描述 获取枚举器的下一个元素
C#函数 bool Next(this Enumerator enumerator)

Neo.Enumerator.Value

功能描述 获取枚举器当前值
C#函数 object Next(this Enumerator enumerator)

Neo.Enumerator.Concat

功能描述 连接两个枚举器
C#函数 Enumerator Concat(Enumerator enumerator1, Enumerator enumerator2)

Neo.Iterator.Create

功能描述 创建一个迭代器
C#函数 Iterator Create(object[] array)
Iterator Create(Dictionary<object, object> map)

Neo.Iterator.Key

功能描述 获取迭代器当前Key值
C#函数 object Key(this Iterator it)

Neo.Iterator.Keys

功能描述 获取迭代器所有Key的迭代器
C#函数 Iterator Keys(this Iterator it)

Neo.Iterator.Values

功能描述 获取迭代器所有Value的迭代器
C#函数 Iterator Values(this Iterator it)

Neo.Iterator.Concat

功能描述 连接两个迭代器
C#函数 Iterator Concat(Iterator iterator1, Iterator iterator2)

Neo.Json.Serialize

功能描述 序列化JSON字符串
C#函数 JObject Serialize(string jsonStr)

Neo.Json.Deserialize

功能描述 反序列化为JSON字符串
C#函数 string Deserialize(JObject jsonObj)

费用

互操作服务 费用 (GAS)
System.ExecutionEngine.GetScriptContainer 0.0000025
System.ExecutionEngine.GetExecutingScriptHash 0.000004
System.ExecutionEngine.GetCallingScriptHash 0.000004
System.ExecutionEngine.GetEntryScriptHash 0.000004
System.Runtime.Platform 0.0000025
System.Runtime.GetTrigger 0.0000025
System.Runtime.CheckWitness 0.0003
System.Runtime.Notify 0.0000025
System.Runtime.Log 0.003
System.Runtime.GetTime 0.0000025
System.Runtime.Serialize 0.001
System.Runtime.Deserialize 0.005
System.Runtime.GetInvocationCounter 0.000004
System.Crypto.Verify 0.01
System.Blockchain.GetHeight 0.000004
System.Blockchain.GetBlock 0.025
System.Blockchain.GetTransaction 0.01
System.Blockchain.GetTransactionHeight 0.01
System.Blockchain.GetTransactionFromBlock 0.01
System.Blockchain.GetContract 0.01
System.Contract.Call 0.01
System.Contract.Destroy 0.01
System.Storage.GetContext 0.000004
System.Storage.GetReadOnlyContext 0.000004
System.Storage.Get 0.01
System.Storage.Put (Key.Size + Value.Size) * GasPerByte
System.Storage.PutEx (Key.Size + Value.Size) * GasPerByte
System.Storage.Delete 0.01
System.StorageContext.AsReadOnly 0.000004
Neo.Native.Deploy 0
Neo.Crypto.CheckSig 0.01
Neo.Crypto.CheckMultiSig 0.01 * n
Neo.Account.IsStandard 0.0003
Neo.Contract.Create (Script.Size + Manifest.Size) * GasPerByte
Neo.Contract.Update (Script.Size + Manifest.Size) * GasPerByte
Neo.Storage.Find 0.01
Neo.Enumerator.Create 0.000004
Neo.Enumerator.Next 0.01
Neo.Enumerator.Value 0.000004
Neo.Enumerator.Concat 0.000004
Neo.Iterator.Create 0.000004
Neo.Iterator.Key 0.000004
Neo.Iterator.Keys 0.000004
Neo.Iterator.Values 0.000004
Neo.Iterator.Concat 0.000004
Neo.Json.Serialize 0.001
Neo.Json.Deserialize 0.005

网路资源访问

合约调用

在合约中调用其他合约

合约中通过开发框架提供的互操作接口System.Contract.Call来调用其他合约 例如在C#中可以如下方式调用:

using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Neo;

namespace MyContract
{
  public class MyContract: SmartContract
  {
    public static readonly byte[] GAS = HexToBytes("0xa1760976db5fcdfab2a9930e8f6ce875b2d18225");
    public static object main(string method, object[] args)
    {
      if (method == "transferGAS") {
        if (args.Length < 3) return false;
        return Contract.Call(GAS, "transfer", args);
      }
    }
  }
}

脚本中调用合约

很多时候需要手动拼接执行脚本,这时候需要使用互操作接口System.Contract.Call与合约的脚本哈希来调用合约。如何使用互操作接口

例如,如果要通过System.Contract.Call来调用合约0x43cf98eddbe047e198a3e5d57006311442a0ca15transfer方法:

PUSHBYTES4  0x00e1f505
PUSHBYTES20 0xfb5fd311a3ae2b2c8ab6b63c10502f9cf58ebeed
PUSHBYTES20 0xa6b9b510a67009e61f4f95115c188437f76dd2d0
PUSH3
PACK                                                      //第三个参数,参数列表
PUSHBYTES4  0x6e616d65                                    //第二个参数,方法名
PUSHBYTES20 0x43cf98eddbe047e198a3e5d57006311442a0ca15    //第一个参数,合约脚本哈希
SYSCALL     0x627d5b52                                    //通过哈希值调用互操作接口

C#代码为:

ScriptBuilder sb        = new ScriptBuilder();
UInt160 scriptHash      = UInt160.Parse("0x43cf98eddbe047e198a3e5d57006311442a0ca15");
string operation        = "transfer";
ContractParameter from  = new ContractParameter(ContractParameterType.Hash160);
ContractParameter to    = new ContractParameter(ContractParameterType.Hash160);
ContractParameter value = new ContractParameter(ContractParameterType.Integer);

from.SetValue("0xa6b9b510a67009e61f4f95115c188437f76dd2d0");
to.SetValue("0xfb5fd311a3ae2b2c8ab6b63c10502f9cf58ebeed");
value.SetValue("100000000");

sb.EmitAppCall(scriptHash, operation, new ContractParameter[]{from, to, value});
byte[] script = sb.ToArray();

public static ScriptBuilder EmitAppCall(this ScriptBuilder sb, UInt160 scriptHash, string operation, params ContractParameter[] args)
{
    for (int i = args.Length - 1; 0 <= i; i--)
        sb.EmitPush(args[i]);
    sb.EmitPush(args.Length);
    sb.Emit(OpCode.PACK);
    sb.EmitPush(operation);
    sb.EmitPush(scriptHash);
    sb.EmitSysCall(InteropService.System_Contract_Call);
    return sb;
}

合约升级

合约部署以后如果需要修改合约的逻辑并且保留存储区的数据,可以使用合约升级,但是需要在旧合约中实现升级接口。在旧合约升级接口中调用Neo.Contract.Update方法。 当在旧合约中调用升级接口时,方法将会根据传入的参数构建一个新的智能合约。如果旧合约有存储区,则会将旧合约的存储区转移至新合约中。升级完成后,旧合约将会被删除,如果旧合约有存储区,则存储区也将被删除。之后旧合约将不可用,需要使用新合约的Hash值。 C#代码如下:

using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Neo;
using Neo.SmartContract.Framework.System;

public static bool Main(string method, params object[] args){
  if (method == "update") {
    if (args.Length < 2) return false;
    if (!Runtime.CheckWitness()) return false;
    byte[] newScript = args[0];
    string manifest = (string)args[1];
    update(newScript, manifest);
    return true;
  }
  return true;
}
void update(byte[] newScript, string manifest)
{
    Contract.Update(newScript, manifest);
}

合约销毁

智能合约支持在发布之后进行销毁操作,但需要在旧合约内预留销毁接口。
合约销毁主要调用了 System.Contract.Destroy 方法

C#代码如下:

using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.System;

public static bool Main(string method, params object[] args){
    if (method == "destroy") {
      destroy();
  }
    return true;
}

void destroy(){
  Contract.Destroy();
}

点击此处查看智能合约英文版