前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >NEO C# 合约编译器原理解析

NEO C# 合约编译器原理解析

作者头像
魂祭心
发布2019-03-12 15:43:19
9310
发布2019-03-12 15:43:19
举报
文章被收录于专栏:魂祭心

NEO C# 合约编译器原理解析

NEO合约编译过程牵涉到几个项目

  1. neo-compiler下的neon项目负责code码转换
  2. neo-devpack-dotnetx下的Neo.SmartContract.Framework负责公共接口定义
  3. neo项目实现了framework中的接口

原理

c#的版本很多,从framework2.0到core2.3版本,语法差异很大,但是底层对应MSIL字节码没有变化,Neo的原理是先使用对应的编译器生成MSIL字节码,再把MSIL字节码转换成NEO vm的code码序列。这样做的好处在与利用了C#现有的语法成果,不必自己在设计一门语言,减少了合约编写的门槛。

大道不过三两行,说穿不值一文钱。下面我会通过一个完整的例子来说明这个流程,希望能藉此帮助更多人了解其中的原理细节,写出效率更好,费用更低的合约。

代码是在github上面找的,NEO-NEP5.1是NEP5的一个token,包含常用的元素,字段,事件与函数。具有常见的数据存储,合约调用及日志信息功能。

代码生成

c# -> MSIL

源码大致结构:实现细节摘除了,需要的请点击上面的链接

代码语言:javascript
复制
using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Services.Neo;
using System;
using System.ComponentModel;
using System.Numerics;

namespace Neo.SmartContract
{
    public class ICO_Template : Framework.SmartContract
    {
        public static string Name() => "GagaPay network token";
        public static string Symbol() => "GTA";
        public static readonly byte[] Owner = "Abdeg1wHpSrfjNzH5edGTabi5jdD9dvncX".ToScriptHash();
        public static byte Decimals() => 8;
        private const ulong factor = 100000000; //decided by Decimals()
        private const ulong total_amount = 1000000000 * factor; //token amount

        [DisplayName("transfer")]
        public static event Action<byte[], byte[], BigInteger> Transferred;

        public static Object Main(string operation, params object[] args)

        public static bool Deploy()

        public static BigInteger TotalSupply()

        public static BigInteger Allowance(byte[] from, byte[] to)

        public static bool Approve(byte[] originator, byte[] to, BigInteger amount)

        public static bool TransferFrom(byte[] originator, byte[] from, byte[] to, BigInteger amountToSend)

        public static bool Transfer(byte[] from, byte[] to, BigInteger value, bool transferFrom)

        public static BigInteger BalanceOf(byte[] address)
    }
}

编译

代码语言:javascript
复制
    dotnet restore
    dotnet publish

编译完成后使用工具查看dll的类布局,其中字段还原没有问题,多了个类构造和构造函数,还有event对应出来的两个add/remove方法,后来在转换过程中都需要清除掉的.事实上在neo中event的更多的只是起到了标识的作用。具体的MSIL CODE太多就不贴上来了,下面提到哪里就贴到哪里.如果需要完整的文件,这里推荐一个常用工具ildasm,用来查看dll的语言信息十分方便。

代码语言:javascript
复制
___[MOD] C:\Users\10844\Desktop\neo\NEP-5.1\NEP-5.1\bin\Debug\netcoreapp2.1\NEP-5.1.dll
   |      M A N I F E S T
   |___[NSP] Neo.SmartContract
   |   |___[CLS] Neo.SmartContract.ICO_Template
   |   |   |     .class public auto ansi beforefieldinit 
   |   |   |      extends [Neo.SmartContract.Framework]Neo.SmartContract.Framework.SmartContract 
   |   |   |___[STF] Owner : public static initonly uint8[]
   |   |   |___[STF] Transferred : private static class [System.Runtime]System.Action`3<uint8[],uint8[],valuetype [System.Runtime.Numerics]System.Numerics.BigInteger>
   |   |   |___[STF] factor : private static literal uint64
   |   |   |___[STF] total_amount : private static literal uint64
   |   |   |___[STM] .cctor : void()
   |   |   |___[MET] .ctor : void()
   |   |   |___[STM] Allowance : valuetype [System.Runtime.Numerics]System.Numerics.BigInteger(uint8[],uint8[])
   |   |   |___[STM] Approve : bool(uint8[],uint8[],valuetype [System.Runtime.Numerics]System.Numerics.BigInteger)
   |   |   |___[STM] BalanceOf : valuetype [System.Runtime.Numerics]System.Numerics.BigInteger(uint8[])
   |   |   |___[STM] Decimals : uint8()
   |   |   |___[STM] Deploy : bool()
   |   |   |___[STM] Main : object(string,object[])
   |   |   |___[STM] Name : string()
   |   |   |___[STM] NotifyErrorAndReturn0 : int32(string)
   |   |   |___[STM] NotifyErrorAndReturnFalse : bool(string)
   |   |   |___[STM] Symbol : string()
   |   |   |___[STM] TotalSupply : valuetype [System.Runtime.Numerics]System.Numerics.BigInteger()
   |   |   |___[STM] Transfer : bool(uint8[],uint8[],valuetype [System.Runtime.Numerics]System.Numerics.BigInteger,bool)
   |   |   |___[STM] TransferFrom : bool(uint8[],uint8[],uint8[],valuetype [System.Runtime.Numerics]System.Numerics.BigInteger)
   |   |   |     add_Transferred : void(class [System.Runtime]System.Action`3<uint8[],uint8[],valuetype [System.Runtime.Numerics]System.Numerics.BigInteger>)
   |   |   |     remove_Transferred : void(class [System.Runtime]System.Action`3<uint8[],uint8[],valuetype [System.Runtime.Numerics]System.Numerics.BigInteger>)
   |   |   |___[EVT] Transferred : class [System.Runtime]System.Action`3<uint8[],uint8[],valuetype [System.Runtime.Numerics]System.Numerics.BigInteger>
   |   |
   |

MSIL -> 合约字节码

MSIL转换合约字节码工具是在neo-compiler/neon中定义的,转换命令为

代码语言:javascript
复制
    dotnet .\neon.dll NEP.dll

这里可能会报错

代码语言:javascript
复制
LoadModule Error:System.Exception: can't parese event type from:System.Action`3<System.Byte[],System.Byte[],System.Numerics.BigInteger>.maybe it is System.Action<xxx> which is defined in mscorlib.dll,copy this dll in.

这个错误估计是底下的库无法正确处理Action导致,这里手动定义下事件,改变下原来Transfer的定义,熟悉C#语法的人应该知道这两种写法几乎是等同的。

代码语言:javascript
复制
    //原来
    [DisplayName("transfer")]
    public static event Action<byte[], byte[], BigInteger> Transferred;

    //修改为
    public delegate void transferDelegete(byte[] s1, byte[] s2, BigInteger  num);
    [DisplayName("transfer")]
    public static event transferDelegete Transferred;

修改完成后重新执行命令‘dotnet .\neon.dll NEP.dll’。看到如下字样即是成功的转换了类库,此时在运行目录下可以看到一个NEP.avm和一个NEP.abi的文件,前者包含了运行所需的字节码,后者仅仅描述了方法和事件信息。

代码语言:javascript
复制
    Neo.Compiler.MSIL console app v2.3.0.8
    Find entrypoint:System.Object Neo.SmartContract.ICO_Template::Main(System.String,System.Object[])
    convert succ
    gen abi succ
    write:NEP.avm
    write:NEP.abi.json
    SUCC

到这neo字节码生成完毕,然后就按官方的方法把这个vm文件发布出去。

代码调用

合约代码入口就是文件的main函数,通常是根据传入的函数名称判断调用到对应的工作函数。下面会通过两个具体函数的执行过程,通过对比三种代码来说明这个编译执行的过程。

部署合约函数流程

入口跳转

c#

代码语言:javascript
复制
    if (operation == "deploy") return Deploy();

MSIL

代码语言:javascript
复制
    IL_007a:  nop
    IL_007b:  ldarg.0
    IL_007c:  ldstr      "deploy"
    IL_0081:  call       bool [mscorlib]System.String::op_Equality(string,
                                                                    string)
    IL_0086:  stloc.s    V_6
    IL_0088:  ldloc.s    V_6
    IL_008a:  brfalse.s  IL_009c
    IL_008c:  call       bool Neo.SmartContract.ICO_Template::Deploy()
    IL_0091:  box        [mscorlib]System.Boolean
    IL_0096:  stloc.2

VM OPCODE

代码语言:javascript
复制
    012D NOP             []
    012E FROMALTSTACK    []
    012F DUP             []
    0130 TOALTSTACK      []
    0131 PUSH0           []
    0132 PICKITEM        []
    0133 6               [deploy]
    013A EQUAL           []
    013B FROMALTSTACK    []
    013C DUP             []
    013D TOALTSTACK      []
    013E PUSH8           []
    013F PUSH2           []
    0140 ROLL            []
    0141 SETITEM         []
    0142 FROMALTSTACK    []
    0143 DUP             []
    0144 TOALTSTACK      []
    0145 PUSH8           []
    0146 PICKITEM        []
    0147 JMPIFNOT        [0013]
    014A NOP             []
    014B CALL_I          [0100BD04]
    0150 FROMALTSTACK    []
    0151 DUP             []
    0152 TOALTSTACK      []
    0153 PUSH4           []
    0154 PUSH2           []
    0155 ROLL            []
    0156 SETITEM         []

其中主要看两条指令,一个是IL_0081/013A,一个是IL_008c/014B,前者就是判断参数是不是depoly,后者是判断成功后进行函数跳转,调用需要执行的函数。

调用部署函数

c#

代码语言:javascript
复制
    if (!Runtime.CheckWitness(Owner)) //ensure that it is the owner calling this method
        return NotifyErrorAndReturnFalse("You are not the Owner of this Smart Contract");

    byte[] total_supply = Storage.Get(Storage.CurrentContext, "totalSupply");

    if (total_supply.Length != 0)
        return NotifyErrorAndReturnFalse("Looks like this method has been allready used");

    Storage.Put(Storage.CurrentContext, Owner, total_amount);
    Storage.Put(Storage.CurrentContext, "totalSupply", total_amount);
    Transferred(null, Owner, total_amount);
    return true;

MSIL

代码语言:javascript
复制
    IL_0000:  nop
    IL_0001:  ldsfld     uint8[] Neo.SmartContract.ICO_Template::Owner
    IL_0006:  call       bool [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Runtime::CheckWitness(uint8[])
    IL_000b:  ldc.i4.0
    IL_000c:  ceq
    IL_000e:  stloc.1
    IL_000f:  ldloc.1
    IL_0010:  brfalse.s  IL_0022
    IL_0012:  ldstr      "You are not the Owner of this Smart Contract"
    IL_0017:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
    IL_001c:  stloc.2
    IL_001d:  br         IL_00a7
    IL_0022:  call       class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
    IL_0027:  ldstr      "totalSupply"
    IL_002c:  call       uint8[] [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Get(class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext,
                                                                                                                    string)
    IL_0031:  stloc.0
    IL_0032:  ldloc.0
    IL_0033:  ldlen
    IL_0034:  ldc.i4.0
    IL_0035:  cgt.un
    IL_0037:  stloc.3
    IL_0038:  ldloc.3
    IL_0039:  brfalse.s  IL_0048
    IL_003b:  ldstr      "Looks like this method has been allready used"
    IL_0040:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
    IL_0045:  stloc.2
    IL_0046:  br.s       IL_00a7
    IL_0048:  call       class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
    IL_004d:  ldsfld     uint8[] Neo.SmartContract.ICO_Template::Owner
    IL_0052:  ldc.i8     0x16345785d8a0000
    IL_005b:  call       valuetype [System.Numerics]System.Numerics.BigInteger [System.Numerics]System.Numerics.BigInteger::op_Implicit(uint64)
    IL_0060:  call       void [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Put(class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext,
                                                                                                                uint8[],
                                                                                                                valuetype [System.Numerics]System.Numerics.BigInteger)
    IL_0065:  nop
    IL_0066:  call       class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
    IL_006b:  ldstr      "totalSupply"
    IL_0070:  ldc.i8     0x16345785d8a0000
    IL_0079:  call       valuetype [System.Numerics]System.Numerics.BigInteger [System.Numerics]System.Numerics.BigInteger::op_Implicit(uint64)
    IL_007e:  call       void [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Put(class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext,
                                                                                                                string,
                                                                                                                valuetype [System.Numerics]System.Numerics.BigInteger)
    IL_0083:  nop
    IL_0084:  ldsfld     class Neo.SmartContract.ICO_Template/helo Neo.SmartContract.ICO_Template::Transferred
    IL_0089:  ldnull
    IL_008a:  ldsfld     uint8[] Neo.SmartContract.ICO_Template::Owner
    IL_008f:  ldc.i8     0x16345785d8a0000
    IL_0098:  call       valuetype [System.Numerics]System.Numerics.BigInteger [System.Numerics]System.Numerics.BigInteger::op_Implicit(uint64)
    IL_009d:  callvirt   instance void Neo.SmartContract.ICO_Template/helo::Invoke(uint8[],
                                                                                    uint8[],
                                                                                    valuetype [System.Numerics]System.Numerics.BigInteger)
    IL_00a2:  nop
    IL_00a3:  ldc.i4.1
    IL_00a4:  stloc.2
    IL_00a5:  br.s       IL_00a7
    IL_00a7:  ldloc.2
    IL_00a8:  ret

VM OPCODE

代码语言:javascript
复制
    060A PUSH4           []//begincode(0)
    060B NEWARRAY        []//(0)
    060C TOALTSTACK      []//(0)
    060D NOP             []
    060E NOP             []
    060F 20              [D9D45BA4DD9497C13A825196A459C6414DA4F020]
    0624 NOP             []
    0625 SYSCALL         [Neo.Runtime.CheckWitness]
    063F PUSH0           []
    0640 NUMEQUAL        []
    0641 FROMALTSTACK    []
    0642 DUP             []
    0643 TOALTSTACK      []
    0644 PUSHT           []
    0645 PUSH2           []
    0646 ROLL            []
    0647 SETITEM         []
    0648 FROMALTSTACK    []
    0649 DUP             []
    064A TOALTSTACK      []
    064B PUSHT           []
    064C PICKITEM        []
    064D JMPIFNOT        [4000]
    0650 44              [You are not the Owner of this Smart Contract]
    067D NOP             []
    067E CALL_I          [01012A0D]
    0683 FROMALTSTACK    []
    0684 DUP             []
    0685 TOALTSTACK      []
    0686 PUSH2           []
    0687 PUSH2           []
    0688 ROLL            []
    0689 SETITEM         []
    068A JMP             [7601]
    068D NOP             []
    068E SYSCALL         [Neo.Storage.GetContext]
    06A6 11              [746F74616C537570706C79]
    06B2 NOP             []
    06B3 SWAP            []//swap 2 param(0)
    06B4 SYSCALL         [Neo.Storage.Get]
    06C5 FROMALTSTACK    []
    06C6 DUP             []
    06C7 TOALTSTACK      []
    06C8 PUSH0           []
    06C9 PUSH2           []
    06CA ROLL            []
    06CB SETITEM         []
    06CC FROMALTSTACK    []
    06CD DUP             []
    06CE TOALTSTACK      []
    06CF PUSH0           []
    06D0 PICKITEM        []
    06D1 ARRAYSIZE       []
    06D2 PUSH0           []
    06D3 GT              []
    06D4 FROMALTSTACK    []
    06D5 DUP             []
    06D6 TOALTSTACK      []
    06D7 PUSH3           []
    06D8 PUSH2           []
    06D9 ROLL            []
    06DA SETITEM         []
    06DB FROMALTSTACK    []
    06DC DUP             []
    06DD TOALTSTACK      []
    06DE PUSH3           []
    06DF PICKITEM        []
    06E0 JMPIFNOT        [4100]
    06E3 45              [Looks like this method has been allready used]
    0711 NOP             []
    0712 CALL_I          [0101960C]
    0717 FROMALTSTACK    []
    0718 DUP             []
    0719 TOALTSTACK      []
    071A PUSH2           []
    071B PUSH2           []
    071C ROLL            []
    071D SETITEM         []
    071E JMP             [E200]
    0721 NOP             []
    0722 SYSCALL         [Neo.Storage.GetContext]
    073A NOP             []
    073B 20              [D9D45BA4DD9497C13A825196A459C6414DA4F020]
    0750 8               [00008A5D78456301]
    0759 NOP             []
    075A PUSH2           []//swap 0 and 2 param(0)
    075B XSWAP           []//(0)
    075C SYSCALL         [Neo.Storage.Put]
    076D NOP             []
    076E NOP             []
    076F SYSCALL         [Neo.Storage.GetContext]
    0787 11              [746F74616C537570706C79]
    0793 8               [00008A5D78456301]
    079C NOP             []
    079D PUSH2           []//swap 0 and 2 param(0)
    079E XSWAP           []//(0)
    079F SYSCALL         [Neo.Storage.Put]
    07B0 NOP             []
    07B1 NOP             []
    07B2 PUSH0           []
    07B3 NOP             []
    07B4 20              [D9D45BA4DD9497C13A825196A459C6414DA4F020]
    07C9 8               [00008A5D78456301]
    07D2 NOP             []
    07D3 PUSH2           []//swap 0 and 2 param(0)
    07D4 XSWAP           []//(0)
    07D5 8               [7472616E73666572]
    07DE PUSH4           []
    07DF PACK            []
    07E0 SYSCALL         [Neo.Runtime.Notify]
    07F4 NOP             []
    07F5 PUSHT           []
    07F6 FROMALTSTACK    []
    07F7 DUP             []
    07F8 TOALTSTACK      []
    07F9 PUSH2           []
    07FA PUSH2           []
    07FB ROLL            []
    07FC SETITEM         []
    07FD JMP             [0300]
    0800 FROMALTSTACK    []
    0801 DUP             []
    0802 TOALTSTACK      []
    0803 PUSH2           []
    0804 PICKITEM        []
    0805 NOP             []
    0806 FROMALTSTACK    []//endcode(0)
    0807 DROP            []//(0)
    0808 RET             []

几个重要的函数调用位置对比:

检查合约所有人

代码语言:javascript
复制
C#:       if (!Runtime.CheckWitness(Owner)) //ensure that it is the owner calling this method
MSIL:        IL_0006:  call       bool [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Runtime::CheckWitness(uint8[])
NEO:        0625 SYSCALL         [Neo.Runtime.CheckWitness]

错误提示:You are not the Owner of this Smart Contract

代码语言:javascript
复制
C#:     return NotifyErrorAndReturnFalse("You are not the Owner of this Smart Contract");
MSIL:   IL_0012:  ldstr      "You are not the Owner of this Smart Contract"
        IL_0017:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
NEO:    0650 44              [You are not the Owner of this Smart Contract]
        067D NOP             []
        067E CALL_I          [01012A0D]

获取当前合约币供应量totalSupply

代码语言:javascript
复制
C#:     byte[] total_supply = Storage.Get(Storage.CurrentContext, "totalSupply");
MSIL:   IL_0022:  call       Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
        IL_0027:  ldstr      "totalSupply"
        IL_002c:  call       uint8[] [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Get
NEO:    068E SYSCALL         [Neo.Storage.GetContext]
        06A6 11              [746F74616C537570706C79]
        06B2 NOP             []
        06B3 SWAP            []//swap 2 param(0)
        06B4 SYSCALL         [Neo.Storage.Get]

错误提示:防止重复调用

代码语言:javascript
复制
C#:     return NotifyErrorAndReturnFalse("Looks like this method has been allready used");
MSIL:   IL_003b:  ldstr      "Looks like this method has been allready used"
        IL_0040:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
NEO:    06E3 45              [Looks like this method has been allready used]
        0711 NOP             []
        0712 CALL_I          [0101960C]

设置初始供应量

代码语言:javascript
复制
C#:     Storage.Put(Storage.CurrentContext, Owner, total_amount);
MSIL:   IL_0048:  call       Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
        IL_004d:  ldsfld     uint8[] Neo.SmartContract.ICO_Template::Owner
        IL_0052:  ldc.i8     0x16345785d8a0000
        IL_005b:  call       valuetype [System.Numerics]System.Numerics.BigInteger [System.Numerics]System.Numerics.BigInteger::op_Implicit(uint64)
        IL_0060:  call       void [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Put
NEO:    0722 SYSCALL         [Neo.Storage.GetContext]
        073A NOP             []
        073B 20              [D9D45BA4DD9497C13A825196A459C6414DA4F020]
        0750 8               [00008A5D78456301]
        0759 NOP             []
        075A PUSH2           []//swap 0 and 2 param(0)
        075B XSWAP           []//(0)
        075C SYSCALL         [Neo.Storage.Put]

打印日志

代码语言:javascript
复制
C#:     Transferred(null, Owner, total_amount);
MSIL:   IL_009d:  callvirt   instance void Neo.SmartContract.ICO_Template/helo::Invoke(uint8[],
                                                                                    uint8[],
                                                                                    valuetype [System.Numerics]System.Numerics.BigInteger)
NEO:    07E0 SYSCALL         [Neo.Runtime.Notify]

转账合约函数调转逻辑

入口跳转

c#

代码语言:javascript
复制
    if (operation == "transfer")
    {
        if (args.Length != 3 || args[0] == null || ((byte[])args[0]).Length == 0 || args[1] == null || ((byte[])args[1]).Length == 0) return NotifyErrorAndReturnFalse("argument count must be 3 and they must not be null");
        byte[] from = (byte[])args[0];
        byte[] to = (byte[])args[1];
        BigInteger value = (BigInteger)args[2];
        return Transfer(from, to, value, false);
    }

MSIL

代码语言:javascript
复制
    IL_022d:  ldarg.0
    IL_022e:  ldstr      "transfer"
    IL_0233:  call       bool [mscorlib]System.String::op_Equality(string,
                                                                    string)
    IL_0238:  stloc.s    V_17
    IL_023a:  ldloc.s    V_17
    IL_023c:  brfalse.s  IL_02b6
    IL_023e:  nop
    IL_023f:  ldarg.1
    IL_0240:  ldlen
    IL_0241:  conv.i4
    IL_0242:  ldc.i4.3
    IL_0243:  bne.un.s   IL_0268
    IL_0245:  ldarg.1
    IL_0246:  ldc.i4.0
    IL_0247:  ldelem.ref
    IL_0248:  brfalse.s  IL_0268
    IL_024a:  ldarg.1
    IL_024b:  ldc.i4.0
    IL_024c:  ldelem.ref
    IL_024d:  castclass  uint8[]
    IL_0252:  ldlen
    IL_0253:  brfalse.s  IL_0268
    IL_0255:  ldarg.1
    IL_0256:  ldc.i4.1
    IL_0257:  ldelem.ref
    IL_0258:  brfalse.s  IL_0268
    IL_025a:  ldarg.1
    IL_025b:  ldc.i4.1
    IL_025c:  ldelem.ref
    IL_025d:  castclass  uint8[]
    IL_0262:  ldlen
    IL_0263:  ldc.i4.0
    IL_0264:  ceq
    IL_0266:  br.s       IL_0269
    IL_0268:  ldc.i4.1
    IL_0269:  stloc.s    V_21
    IL_026b:  ldloc.s    V_21
    IL_026d:  brfalse.s  IL_0284
    IL_026f:  ldstr      "argument count must be 3 and they must not be null"
    IL_0274:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
    IL_0279:  box        [mscorlib]System.Boolean
    IL_027e:  stloc.2
    IL_027f:  br         IL_0326
    IL_0284:  ldarg.1
    IL_0285:  ldc.i4.0
    IL_0286:  ldelem.ref
    IL_0287:  castclass  uint8[]
    IL_028c:  stloc.s    V_18
    IL_028e:  ldarg.1
    IL_028f:  ldc.i4.1
    IL_0290:  ldelem.ref
    IL_0291:  castclass  uint8[]
    IL_0296:  stloc.s    V_19
    IL_0298:  ldarg.1
    IL_0299:  ldc.i4.2
    IL_029a:  ldelem.ref
    IL_029b:  unbox.any  [System.Numerics]System.Numerics.BigInteger
    IL_02a0:  stloc.s    V_20
    IL_02a2:  ldloc.s    V_18
    IL_02a4:  ldloc.s    V_19
    IL_02a6:  ldloc.s    V_20
    IL_02a8:  ldc.i4.0
    IL_02a9:  call       bool Neo.SmartContract.ICO_Template::Transfer(uint8[],
                                                                        uint8[],
                                                                        valuetype [System.Numerics]System.Numerics.BigInteger,
                                                                        bool)
    IL_02ae:  box        [mscorlib]System.Boolean
    IL_02b3:  stloc.2
    IL_02b4:  br.s       IL_0326

VM OPCODE

代码语言:javascript
复制
    03CB FROMALTSTACK    []
    03CC DUP             []
    03CD TOALTSTACK      []
    03CE PUSH4           []
    03CF PUSH2           []
    03D0 ROLL            []
    03D1 SETITEM         []
    03D2 JMP             [FF01]
    03D5 FROMALTSTACK    []
    03D6 DUP             []
    03D7 TOALTSTACK      []
    03D8 PUSH0           []
    03D9 PICKITEM        []
    03DA 8               [transfer]
    03E3 EQUAL           []   //op_Equality
    03E4 FROMALTSTACK    []
    03E5 DUP             []
    03E6 TOALTSTACK      []
    03E7 PUSHBYTES1      []
    03E9 PUSH2           []
    03EA ROLL            []
    03EB SETITEM         []
    03EC FROMALTSTACK    []
    03ED DUP             []
    03EE TOALTSTACK      []
    03EF PUSHBYTES1      []
    03F1 PICKITEM        []
    03F2 JMPIFNOT        [00F8]
    03F5 NOP             []
    03F6 FROMALTSTACK    []
    03F7 DUP             []
    03F8 TOALTSTACK      []
    03F9 PUSHT           []
    03FA PICKITEM        []
    03FB ARRAYSIZE       []
    03FC PUSH3           []
    03FD ABS             []
    03FE SWAP            []
    03FF ABS             []
    0400 SWAP            []
    0401 NUMNOTEQUAL     []
    0402 JMPIF           [2F00]
    0405 FROMALTSTACK    []
    0406 DUP             []
    0407 TOALTSTACK      []
    0408 PUSHT           []
    0409 PICKITEM        []
    040A PUSH0           []
    040B PICKITEM        []
    040C JMPIFNOT        [0025]
    040F FROMALTSTACK    []
    0410 DUP             []
    0411 TOALTSTACK      []
    0412 PUSHT           []
    0413 PICKITEM        []
    0414 PUSH0           []
    0415 PICKITEM        []
    0416 ARRAYSIZE       []
    0417 JMPIFNOT        [001A]
    041A FROMALTSTACK    []
    041B DUP             []
    041C TOALTSTACK      []
    041D PUSHT           []
    041E PICKITEM        []
    041F PUSHT           []
    0420 PICKITEM        []
    0421 JMPIFNOT        [0010]
    0424 FROMALTSTACK    []
    0425 DUP             []
    0426 TOALTSTACK      []
    0427 PUSHT           []
    0428 PICKITEM        []
    0429 PUSHT           []
    042A PICKITEM        []
    042B ARRAYSIZE       []
    042C PUSH0           []
    042D NUMEQUAL        []
    042E JMP             [0400]
    0431 PUSHT           []
    0432 FROMALTSTACK    []
    0433 DUP             []
    0434 TOALTSTACK      []
    0435 PUSHBYTES1      []
    0437 PUSH2           []
    0438 ROLL            []
    0439 SETITEM         []
    043A FROMALTSTACK    []
    043B DUP             []
    043C TOALTSTACK      []
    043D PUSHBYTES1      []
    043F PICKITEM        []
    0440 JMPIFNOT        [0046]
    0443 50              [argument count must be 3 and they must not be null]
    0476 NOP             []
    0477 CALL_I          [0101310F]  //NotifyErrorAndReturnFalse
    047C FROMALTSTACK    []
    047D DUP             []
    047E TOALTSTACK      []
    047F PUSH4           []
    0480 PUSH2           []
    0481 ROLL            []
    0482 SETITEM         []
    0483 JMP             [4E01]
    0486 FROMALTSTACK    []
    0487 DUP             []
    0488 TOALTSTACK      []
    0489 PUSHT           []
    048A PICKITEM        []
    048B PUSH0           []
    048C PICKITEM        []
    048D FROMALTSTACK    []
    048E DUP             []
    048F TOALTSTACK      []
    0490 PUSHBYTES1      []
    0492 PUSH2           []
    0493 ROLL            []
    0494 SETITEM         []
    0495 FROMALTSTACK    []
    0496 DUP             []
    0497 TOALTSTACK      []
    0498 PUSHT           []
    0499 PICKITEM        []
    049A PUSHT           []
    049B PICKITEM        []
    049C FROMALTSTACK    []
    049D DUP             []
    049E TOALTSTACK      []
    049F PUSHBYTES1      []
    04A1 PUSH2           []
    04A2 ROLL            []
    04A3 SETITEM         []
    04A4 FROMALTSTACK    []
    04A5 DUP             []
    04A6 TOALTSTACK      []
    04A7 PUSHT           []
    04A8 PICKITEM        []
    04A9 PUSH2           []
    04AA PICKITEM        []
    04AB FROMALTSTACK    []
    04AC DUP             []
    04AD TOALTSTACK      []
    04AE PUSHBYTES1      []
    04B0 PUSH2           []
    04B1 ROLL            []
    04B2 SETITEM         []
    04B3 FROMALTSTACK    []
    04B4 DUP             []
    04B5 TOALTSTACK      []
    04B6 PUSHBYTES1      []
    04B8 PICKITEM        []
    04B9 FROMALTSTACK    []
    04BA DUP             []
    04BB TOALTSTACK      []
    04BC PUSHBYTES1      []
    04BE PICKITEM        []
    04BF FROMALTSTACK    []
    04C0 DUP             []
    04C1 TOALTSTACK      []
    04C2 PUSHBYTES1      []
    04C4 PICKITEM        []
    04C5 PUSH0           []
    04C6 NOP             []
    04C7 PUSH3           []//load3(0)
    04C8 PICK            []//(0)
    04C9 PUSHT           []//load01(0)
    04CA PICK            []//(0)
    04CB PUSH5           []//save to32(0)
    04CC XSWAP           []//(0)
    04CD DROP            []//(0)
    04CE PUSHT           []//save to01(0)
    04CF XSWAP           []//(0)
    04D0 DROP            []//(0)
    04D1 PUSH2           []//load2(0)
    04D2 PICK            []//(0)
    04D3 PUSH2           []//load11(0)
    04D4 PICK            []//(0)
    04D5 PUSH4           []//save to22(0)
    04D6 XSWAP           []//(0)
    04D7 DROP            []//(0)
    04D8 PUSH2           []//save to11(0)
    04D9 XSWAP           []//(0)
    04DA DROP            []//(0)
    04DB CALL_I          [0104E60A] //Transfer
    04E0 FROMALTSTACK    []
    04E1 DUP             []
    04E2 TOALTSTACK      []
    04E3 PUSH4           []
    04E4 PUSH2           []
    04E5 ROLL            []
    04E6 SETITEM         []

指令IL_0233/03E3用于确认要调用的函数是否是transfer,IL_0274/0477 用于打印错误日志信息,指令IL_02a9/04DB调用转账函数。

调用转账函数

c#

代码语言:javascript
复制
    if (to == null || to.Length != 20)
    return NotifyErrorAndReturnFalse("To value must not be empty and have size of 20");

    if (from == null || from.Length != 20)
        return NotifyErrorAndReturnFalse("From value must not be empty and have size of 20");

    if (value <= 0) return NotifyErrorAndReturnFalse("Try to send more than 0 tokens");
    if (!transferFrom && !Runtime.CheckWitness(from)) return NotifyErrorAndReturnFalse("Owner of the wallet is not involved in this invoke");
    if (from == to) return true;
    BigInteger from_value = Storage.Get(Storage.CurrentContext, from).AsBigInteger();
    if (from_value < value) return NotifyErrorAndReturnFalse("Insufficient funds");
    if (from_value == value)
        Storage.Delete(Storage.CurrentContext, from);
    else
        Storage.Put(Storage.CurrentContext, from, from_value - value);
    BigInteger to_value = Storage.Get(Storage.CurrentContext, to).AsBigInteger();
    Storage.Put(Storage.CurrentContext, to, to_value + value);
    Transferred(from, to, value);
    return true;

MSIL

代码语言:javascript
复制
    IL_0000:  nop
    IL_0001:  ldarg.1
    IL_0002:  brfalse.s  IL_0010
    IL_0004:  ldarg.1
    IL_0005:  ldlen
    IL_0006:  conv.i4
    IL_0007:  ldc.i4.s   20
    IL_0009:  ceq
    IL_000b:  ldc.i4.0
    IL_000c:  ceq
    IL_000e:  br.s       IL_0011
    IL_0010:  ldc.i4.1
    IL_0011:  stloc.2
    IL_0012:  ldloc.2
    IL_0013:  brfalse.s  IL_0025
    IL_0015:  ldstr      "To value must not be empty and have size of 20"
    IL_001a:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
    IL_001f:  stloc.3
    IL_0020:  br         IL_012e
    IL_0025:  ldarg.0
    IL_0026:  brfalse.s  IL_0034
    IL_0028:  ldarg.0
    IL_0029:  ldlen
    IL_002a:  conv.i4
    IL_002b:  ldc.i4.s   20
    IL_002d:  ceq
    IL_002f:  ldc.i4.0
    IL_0030:  ceq
    IL_0032:  br.s       IL_0035
    IL_0034:  ldc.i4.1
    IL_0035:  stloc.s    V_4
    IL_0037:  ldloc.s    V_4
    IL_0039:  brfalse.s  IL_004b
    IL_003b:  ldstr      "From value must not be empty and have size of 20"
    IL_0040:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
    IL_0045:  stloc.3
    IL_0046:  br         IL_012e
    IL_004b:  ldarg.2
    IL_004c:  ldc.i4.0
    IL_004d:  conv.i8
    IL_004e:  call       bool [System.Numerics]System.Numerics.BigInteger::op_LessThanOrEqual(valuetype [System.Numerics]System.Numerics.BigInteger,
                                                                                            int64)
    IL_0053:  stloc.s    V_5
    IL_0055:  ldloc.s    V_5
    IL_0057:  brfalse.s  IL_0069
    IL_0059:  ldstr      "Try to send more than 0 tokens"
    IL_005e:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
    IL_0063:  stloc.3
    IL_0064:  br         IL_012e
    IL_0069:  ldarg.3
    IL_006a:  brtrue.s   IL_0077
    IL_006c:  ldarg.0
    IL_006d:  call       bool [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Runtime::CheckWitness(uint8[])
    IL_0072:  ldc.i4.0
    IL_0073:  ceq
    IL_0075:  br.s       IL_0078
    IL_0077:  ldc.i4.0
    IL_0078:  stloc.s    V_6
    IL_007a:  ldloc.s    V_6
    IL_007c:  brfalse.s  IL_008e
    IL_007e:  ldstr      "Owner of the wallet is not involved in this invoke"
    IL_0083:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
    IL_0088:  stloc.3
    IL_0089:  br         IL_012e
    IL_008e:  ldarg.0
    IL_008f:  ldarg.1
    IL_0090:  ceq
    IL_0092:  stloc.s    V_7
    IL_0094:  ldloc.s    V_7
    IL_0096:  brfalse.s  IL_009f
    IL_0098:  ldc.i4.1
    IL_0099:  stloc.3
    IL_009a:  br         IL_012e
    IL_009f:  call       class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
    IL_00a4:  ldarg.0
    IL_00a5:  call       uint8[] [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Get(class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext,
                                                                                                                    uint8[])
    IL_00aa:  call       valuetype [System.Numerics]System.Numerics.BigInteger [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Helper::AsBigInteger(uint8[])
    IL_00af:  stloc.0
    IL_00b0:  ldloc.0
    IL_00b1:  ldarg.2
    IL_00b2:  call       bool [System.Numerics]System.Numerics.BigInteger::op_LessThan(valuetype [System.Numerics]System.Numerics.BigInteger,
                                                                                        valuetype [System.Numerics]System.Numerics.BigInteger)
    IL_00b7:  stloc.s    V_8
    IL_00b9:  ldloc.s    V_8
    IL_00bb:  brfalse.s  IL_00ca
    IL_00bd:  ldstr      "Insufficient funds"
    IL_00c2:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
    IL_00c7:  stloc.3
    IL_00c8:  br.s       IL_012e
    IL_00ca:  ldloc.0
    IL_00cb:  ldarg.2
    IL_00cc:  call       bool [System.Numerics]System.Numerics.BigInteger::op_Equality(valuetype [System.Numerics]System.Numerics.BigInteger,
                                                                                        valuetype [System.Numerics]System.Numerics.BigInteger)
    IL_00d1:  stloc.s    V_9
    IL_00d3:  ldloc.s    V_9
    IL_00d5:  brfalse.s  IL_00e5
    IL_00d7:  call       class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
    IL_00dc:  ldarg.0
    IL_00dd:  call       void [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Delete(class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext,
                                                                                                                    uint8[])
    IL_00e2:  nop
    IL_00e3:  br.s       IL_00f8
    IL_00e5:  call       class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
    IL_00ea:  ldarg.0
    IL_00eb:  ldloc.0
    IL_00ec:  ldarg.2
    IL_00ed:  call       valuetype [System.Numerics]System.Numerics.BigInteger [System.Numerics]System.Numerics.BigInteger::op_Subtraction
    IL_00f2:  call       void [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Put(class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext,
                                                                                                                uint8[],
                                                                                                                valuetype [System.Numerics]System.Numerics.BigInteger)
    IL_00f7:  nop
    IL_00f8:  call       class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
    IL_00fd:  ldarg.1
    IL_00fe:  call       uint8[] [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Get(class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext,
                                                                                                                    uint8[])
    IL_0103:  call       valuetype [System.Numerics]System.Numerics.BigInteger [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Helper::AsBigInteger(uint8[])
    IL_0108:  stloc.1
    IL_0109:  call       class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
    IL_010e:  ldarg.1
    IL_010f:  ldloc.1
    IL_0110:  ldarg.2
    IL_0111:  call       valuetype [System.Numerics]System.Numerics.BigInteger [System.Numerics]System.Numerics.BigInteger::op_Addition
    IL_0116:  call       void [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Put(class [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.StorageContext,
                                                                                                                uint8[],
                                                                                                                valuetype [System.Numerics]System.Numerics.BigInteger)
    IL_011b:  nop
    IL_011c:  ldsfld     class Neo.SmartContract.ICO_Template/helo Neo.SmartContract.ICO_Template::Transferred
    IL_0121:  ldarg.0
    IL_0122:  ldarg.1
    IL_0123:  ldarg.2
    IL_0124:  callvirt   instance void Neo.SmartContract.ICO_Template/helo::Invoke(uint8[],
                                                                                    uint8[],
                                                                                    valuetype [System.Numerics]System.Numerics.BigInteger)
    IL_0129:  nop
    IL_012a:  ldc.i4.1
    IL_012b:  stloc.3
    IL_012c:  br.s       IL_012e
    IL_012e:  ldloc.3
    IL_012f:  ret

VM OPCODE

代码语言:javascript
复制
    0FC3 PUSH14          []//begincode(0)
    0FC4 NEWARRAY        []//(0)
    0FC5 TOALTSTACK      []//(0)
    0FC6 FROMALTSTACK    []//set param:0(0)
    0FC7 DUP             []
    0FC8 TOALTSTACK      []
    0FC9 PUSH0           []//(0)
    0FCA PUSH2           []//(0)
    0FCB ROLL            []
    0FCC SETITEM         []
    0FCD FROMALTSTACK    []//set param:1(0)
    0FCE DUP             []
    0FCF TOALTSTACK      []
    0FD0 PUSHT           []//(0)
    0FD1 PUSH2           []//(0)
    0FD2 ROLL            []
    0FD3 SETITEM         []
    0FD4 FROMALTSTACK    []//set param:2(0)
    0FD5 DUP             []
    0FD6 TOALTSTACK      []
    0FD7 PUSH2           []//(0)
    0FD8 PUSH2           []//(0)
    0FD9 ROLL            []
    0FDA SETITEM         []
    0FDB FROMALTSTACK    []//set param:3(0)
    0FDC DUP             []
    0FDD TOALTSTACK      []
    0FDE PUSH3           []//(0)
    0FDF PUSH2           []//(0)
    0FE0 ROLL            []
    0FE1 SETITEM         []
    0FE2 NOP             []
    0FE3 FROMALTSTACK    []
    0FE4 DUP             []
    0FE5 TOALTSTACK      []
    0FE6 PUSHT           []
    0FE7 PICKITEM        []
    0FE8 JMPIFNOT        [1100]
    0FEB FROMALTSTACK    []
    0FEC DUP             []
    0FED TOALTSTACK      []
    0FEE PUSHT           []
    0FEF PICKITEM        []
    0FF0 ARRAYSIZE       []
    0FF1 PUSHBYTES1      [14]
    0FF3 NUMEQUAL        []
    0FF4 PUSH0           []
    0FF5 NUMEQUAL        []
    0FF6 JMP             [0400]
    0FF9 PUSHT           []
    0FFA FROMALTSTACK    []
    0FFB DUP             []
    0FFC TOALTSTACK      []
    0FFD PUSH6           []
    0FFE PUSH2           []
    0FFF ROLL            []
    1000 SETITEM         []
    1001 FROMALTSTACK    []
    1002 DUP             []
    1003 TOALTSTACK      []
    1004 PUSH6           []
    1005 PICKITEM        []
    1006 JMPIFNOT        [4200]
    1009 46              [To value must not be empty and have size of 20]
    1038 NOP             []
    1039 CALL_I          [01016F03]
    103E FROMALTSTACK    []
    103F DUP             []
    1040 TOALTSTACK      []
    1041 PUSH7           []
    1042 PUSH2           []
    1043 ROLL            []
    1044 SETITEM         []
    1045 JMP             [0D03]
    1048 FROMALTSTACK    []
    1049 DUP             []
    104A TOALTSTACK      []
    104B PUSH0           []
    104C PICKITEM        []
    104D JMPIFNOT        [1100]
    1050 FROMALTSTACK    []
    1051 DUP             []
    1052 TOALTSTACK      []
    1053 PUSH0           []
    1054 PICKITEM        []
    1055 ARRAYSIZE       []
    1056 PUSHBYTES1      [14]
    1058 NUMEQUAL        []
    1059 PUSH0           []
    105A NUMEQUAL        []
    105B JMP             [0400]
    105E PUSHT           []
    105F FROMALTSTACK    []
    1060 DUP             []
    1061 TOALTSTACK      []
    1062 PUSH8           []
    1063 PUSH2           []
    1064 ROLL            []
    1065 SETITEM         []
    1066 FROMALTSTACK    []
    1067 DUP             []
    1068 TOALTSTACK      []
    1069 PUSH8           []
    106A PICKITEM        []
    106B JMPIFNOT        [4400]
    106E 48              [From value must not be empty and have size of 20]
    109F NOP             []
    10A0 CALL_I          [01010803]
    10A5 FROMALTSTACK    []
    10A6 DUP             []
    10A7 TOALTSTACK      []
    10A8 PUSH7           []
    10A9 PUSH2           []
    10AA ROLL            []
    10AB SETITEM         []
    10AC JMP             [A602]
    10AF FROMALTSTACK    []
    10B0 DUP             []
    10B1 TOALTSTACK      []
    10B2 PUSH2           []
    10B3 PICKITEM        []
    10B4 PUSH0           []
    10B5 LTE             []
    10B6 FROMALTSTACK    []
    10B7 DUP             []
    10B8 TOALTSTACK      []
    10B9 PUSH9           []
    10BA PUSH2           []
    10BB ROLL            []
    10BC SETITEM         []
    10BD FROMALTSTACK    []
    10BE DUP             []
    10BF TOALTSTACK      []
    10C0 PUSH9           []
    10C1 PICKITEM        []
    10C2 JMPIFNOT        [3200]
    10C5 30              [Try to send more than 0 tokens]
    10E4 NOP             []
    10E5 CALL_I          [0101C302]
    10EA FROMALTSTACK    []
    10EB DUP             []
    10EC TOALTSTACK      []
    10ED PUSH7           []
    10EE PUSH2           []
    10EF ROLL            []
    10F0 SETITEM         []
    10F1 JMP             [6102]
    10F4 FROMALTSTACK    []
    10F5 DUP             []
    10F6 TOALTSTACK      []
    10F7 PUSH3           []
    10F8 PICKITEM        []
    10F9 JMPIF           [2800]
    10FC FROMALTSTACK    []
    10FD DUP             []
    10FE TOALTSTACK      []
    10FF PUSH0           []
    1100 PICKITEM        []
    1101 NOP             []
    1102 SYSCALL         [Neo.Runtime.CheckWitness]
    111C PUSH0           []
    111D NUMEQUAL        []
    111E JMP             [0400]
    1121 PUSH0           []
    1122 FROMALTSTACK    []
    1123 DUP             []
    1124 TOALTSTACK      []
    1125 PUSH10          []
    1126 PUSH2           []
    1127 ROLL            []
    1128 SETITEM         []
    1129 FROMALTSTACK    []
    112A DUP             []
    112B TOALTSTACK      []
    112C PUSH10          []
    112D PICKITEM        []
    112E JMPIFNOT        [4600]
    1131 50              [Owner of the wallet is not involved in this invoke]
    1164 NOP             []
    1165 CALL_I          [01014302]
    116A FROMALTSTACK    []
    116B DUP             []
    116C TOALTSTACK      []
    116D PUSH7           []
    116E PUSH2           []
    116F ROLL            []
    1170 SETITEM         []
    1171 JMP             [E101]
    1174 FROMALTSTACK    []
    1175 DUP             []
    1176 TOALTSTACK      []
    1177 PUSH0           []
    1178 PICKITEM        []
    1179 FROMALTSTACK    []
    117A DUP             []
    117B TOALTSTACK      []
    117C PUSHT           []
    117D PICKITEM        []
    117E NUMEQUAL        []
    117F FROMALTSTACK    []
    1180 DUP             []
    1181 TOALTSTACK      []
    1182 PUSH11          []
    1183 PUSH2           []
    1184 ROLL            []
    1185 SETITEM         []
    1186 FROMALTSTACK    []
    1187 DUP             []
    1188 TOALTSTACK      []
    1189 PUSH11          []
    118A PICKITEM        []
    118B JMPIFNOT        [0E00]
    118E PUSHT           []
    118F FROMALTSTACK    []
    1190 DUP             []
    1191 TOALTSTACK      []
    1192 PUSH7           []
    1193 PUSH2           []
    1194 ROLL            []
    1195 SETITEM         []
    1196 JMP             [BC01]
    1199 NOP             []
    119A SYSCALL         [Neo.Storage.GetContext]
    11B2 FROMALTSTACK    []
    11B3 DUP             []
    11B4 TOALTSTACK      []
    11B5 PUSH0           []
    11B6 PICKITEM        []
    11B7 NOP             []
    11B8 SWAP            []//swap 2 param(0)
    11B9 SYSCALL         [Neo.Storage.Get]
    11CA FROMALTSTACK    []
    11CB DUP             []
    11CC TOALTSTACK      []
    11CD PUSH4           []
    11CE PUSH2           []
    11CF ROLL            []
    11D0 SETITEM         []
    11D1 FROMALTSTACK    []
    11D2 DUP             []
    11D3 TOALTSTACK      []
    11D4 PUSH4           []
    11D5 PICKITEM        []
    11D6 FROMALTSTACK    []
    11D7 DUP             []
    11D8 TOALTSTACK      []
    11D9 PUSH2           []
    11DA PICKITEM        []
    11DB LT              []
    11DC FROMALTSTACK    []
    11DD DUP             []
    11DE TOALTSTACK      []
    11DF PUSH12          []
    11E0 PUSH2           []
    11E1 ROLL            []
    11E2 SETITEM         []
    11E3 FROMALTSTACK    []
    11E4 DUP             []
    11E5 TOALTSTACK      []
    11E6 PUSH12          []
    11E7 PICKITEM        []
    11E8 JMPIFNOT        [2600]
    11EB 18              [496E73756666696369656E742066756E6473]
    11FE NOP             []
    11FF CALL_I          [0101A901]
    1204 FROMALTSTACK    []
    1205 DUP             []
    1206 TOALTSTACK      []
    1207 PUSH7           []
    1208 PUSH2           []
    1209 ROLL            []
    120A SETITEM         []
    120B JMP             [4701]
    120E FROMALTSTACK    []
    120F DUP             []
    1210 TOALTSTACK      []
    1211 PUSH4           []
    1212 PICKITEM        []
    1213 FROMALTSTACK    []
    1214 DUP             []
    1215 TOALTSTACK      []
    1216 PUSH2           []
    1217 PICKITEM        []
    1218 NUMEQUAL        []
    1219 FROMALTSTACK    []
    121A DUP             []
    121B TOALTSTACK      []
    121C PUSH13          []
    121D PUSH2           []
    121E ROLL            []
    121F SETITEM         []
    1220 FROMALTSTACK    []
    1221 DUP             []
    1222 TOALTSTACK      []
    1223 PUSH13          []
    1224 PICKITEM        []
    1225 JMPIFNOT        [3B00]
    1228 NOP             []
    1229 SYSCALL         [Neo.Storage.GetContext]
    1241 FROMALTSTACK    []
    1242 DUP             []
    1243 TOALTSTACK      []
    1244 PUSH0           []
    1245 PICKITEM        []
    1246 NOP             []
    1247 SWAP            []//swap 2 param(0)
    1248 SYSCALL         [Neo.Storage.Delete]
    125C NOP             []
    125D JMP             [4100]
    1260 NOP             []
    1261 SYSCALL         [Neo.Storage.GetContext]
    1279 FROMALTSTACK    []
    127A DUP             []
    127B TOALTSTACK      []
    127C PUSH0           []
    127D PICKITEM        []
    127E FROMALTSTACK    []
    127F DUP             []
    1280 TOALTSTACK      []
    1281 PUSH4           []
    1282 PICKITEM        []
    1283 FROMALTSTACK    []
    1284 DUP             []
    1285 TOALTSTACK      []
    1286 PUSH2           []
    1287 PICKITEM        []
    1288 SUB             []
    1289 NOP             []
    128A PUSH2           []//swap 0 and 2 param(0)
    128B XSWAP           []//(0)
    128C SYSCALL         [Neo.Storage.Put]
    129D NOP             []
    129E NOP             []
    129F SYSCALL         [Neo.Storage.GetContext]
    12B7 FROMALTSTACK    []
    12B8 DUP             []
    12B9 TOALTSTACK      []
    12BA PUSHT           []
    12BB PICKITEM        []
    12BC NOP             []
    12BD SWAP            []//swap 2 param(0)
    12BE SYSCALL         [Neo.Storage.Get]
    12CF FROMALTSTACK    []
    12D0 DUP             []
    12D1 TOALTSTACK      []
    12D2 PUSH5           []
    12D3 PUSH2           []
    12D4 ROLL            []
    12D5 SETITEM         []
    12D6 NOP             []
    12D7 SYSCALL         [Neo.Storage.GetContext]
    12EF FROMALTSTACK    []
    12F0 DUP             []
    12F1 TOALTSTACK      []
    12F2 PUSHT           []
    12F3 PICKITEM        []
    12F4 FROMALTSTACK    []
    12F5 DUP             []
    12F6 TOALTSTACK      []
    12F7 PUSH5           []
    12F8 PICKITEM        []
    12F9 FROMALTSTACK    []
    12FA DUP             []
    12FB TOALTSTACK      []
    12FC PUSH2           []
    12FD PICKITEM        []
    12FE ADD             []
    12FF NOP             []
    1300 PUSH2           []//swap 0 and 2 param(0)
    1301 XSWAP           []//(0)
    1302 SYSCALL         [Neo.Storage.Put]
    1313 NOP             []
    1314 NOP             []
    1315 FROMALTSTACK    []
    1316 DUP             []
    1317 TOALTSTACK      []
    1318 PUSH0           []
    1319 PICKITEM        []
    131A FROMALTSTACK    []
    131B DUP             []
    131C TOALTSTACK      []
    131D PUSHT           []
    131E PICKITEM        []
    131F FROMALTSTACK    []
    1320 DUP             []
    1321 TOALTSTACK      []
    1322 PUSH2           []
    1323 PICKITEM        []
    1324 NOP             []
    1325 PUSH2           []//swap 0 and 2 param(0)
    1326 XSWAP           []//(0)
    1327 8               [7472616E73666572]
    1330 PUSH4           []
    1331 PACK            []
    1332 SYSCALL         [Neo.Runtime.Notify]
    1346 NOP             []
    1347 PUSHT           []
    1348 FROMALTSTACK    []
    1349 DUP             []
    134A TOALTSTACK      []
    134B PUSH7           []
    134C PUSH2           []
    134D ROLL            []
    134E SETITEM         []
    134F JMP             [0300]
    1352 FROMALTSTACK    []
    1353 DUP             []
    1354 TOALTSTACK      []
    1355 PUSH7           []
    1356 PICKITEM        []
    1357 NOP             []
    1358 FROMALTSTACK    []//endcode(0)
    1359 DROP            []//(0)
    135A RET             []

提示转出地址不合法错误

代码语言:javascript
复制
C#:     return NotifyErrorAndReturnFalse("To value must not be empty and have size of 20");
MSIL:   IL_003b:  ldstr      "From value must not be empty and have size of 20"
        IL_0040:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
NEO:    1009 46              [To value must not be empty and have size of 20]
        1038 NOP             []
        1039 CALL_I          [01016F03]

提示转入地址不合法错误

代码语言:javascript
复制
C#:     return NotifyErrorAndReturnFalse("From value must not be empty and have size of 20");
MSIL:   IL_0015:  ldstr      "To value must not be empty and have size of 20"
        IL_001a:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
NEO:    106E 48              [From value must not be empty and have size of 20]
        109F NOP             []
        10A0 CALL_I          [01010803]

提示资产错误

代码语言:javascript
复制
C#:     return NotifyErrorAndReturnFalse("Try to send more than 0 tokens");  
MSIL:   IL_0059:  ldstr      "Try to send more than 0 tokens"
        IL_005e:  call       bool Neo.SmartContract.ICO_Template::NotifyErrorAndReturnFalse(string)
NEO:    10C5 30              [Try to send more than 0 tokens]
        10E4 NOP             []
        10E5 CALL_I          [0101C302]

获取转出地址资产

代码语言:javascript
复制
C#:     BigInteger from_value = Storage.Get(Storage.CurrentContext, from).AsBigInteger();   
MSIL:   IL_009f:  call   Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
        IL_00a4:  ldarg.0
        IL_00a5:  call       uint8[] [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Get
NEO:    119A SYSCALL         [Neo.Storage.GetContext]
        11B2 FROMALTSTACK    []
        11B3 DUP             []
        11B4 TOALTSTACK      []
        11B5 PUSH0           []
        11B6 PICKITEM        []
        11B7 NOP             []
        11B8 SWAP            []//swap 2 param(0)
        11B9 SYSCALL         [Neo.Storage.Get]

如果转出地址交易后金额为0删除该地址

代码语言:javascript
复制
C#:     Storage.Delete(Storage.CurrentContext, from);
MSIL:   IL_00d7:  call       Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
        IL_00dc:  ldarg.0
        IL_00dd:  call       void [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Delete
NEO:    1229 SYSCALL         [Neo.Storage.GetContext]
        1241 FROMALTSTACK    []
        1242 DUP             []
        1243 TOALTSTACK      []
        1244 PUSH0           []
        1245 PICKITEM        []
        1246 NOP             []
        1247 SWAP            []//swap 2 param(0)
        1248 SYSCALL         [Neo.Storage.Delete]

如果转出地址交易后还有余额,则重新设置该地址余额

代码语言:javascript
复制
C#:     Storage.Put(Storage.CurrentContext, from, from_value - value);
MSIL:   IL_00e5:  call      Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
        IL_00ea:  ldarg.0
        IL_00eb:  ldloc.0
        IL_00ec:  ldarg.2
        IL_00ed:  call       valuetype [System.Numerics]System.Numerics.BigInteger [System.Numerics]System.Numerics.BigInteger::op_Subtraction
        IL_00f2:  call       void [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Put
NEO:    1261 SYSCALL         [Neo.Storage.GetContext]
        1279 FROMALTSTACK    []
        127A DUP             []
        127B TOALTSTACK      []
        127C PUSH0           []
        127D PICKITEM        []
        127E FROMALTSTACK    []
        127F DUP             []
        1280 TOALTSTACK      []
        1281 PUSH4           []
        1282 PICKITEM        []
        1283 FROMALTSTACK    []
        1284 DUP             []
        1285 TOALTSTACK      []
        1286 PUSH2           []
        1287 PICKITEM        []
        1288 SUB             []
        1289 NOP             []
        128A PUSH2           []//swap 0 and 2 param(0)
        128B XSWAP           []//(0)
        128C SYSCALL         [Neo.Storage.Put]

设置转出地址交易后余额

代码语言:javascript
复制
C#:     Storage.Put(Storage.CurrentContext, to, to_value + value);
MSIL:   IL_0109:  call       Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::get_CurrentContext()
        IL_010e:  ldarg.1
        IL_010f:  ldloc.1
        IL_0110:  ldarg.2
        IL_0111:  call       valuetype [System.Numerics]System.Numerics.BigInteger [System.Numerics]System.Numerics.BigInteger::op_Addition
        IL_0116:  call       void [Neo.SmartContract.Framework]Neo.SmartContract.Framework.Services.Neo.Storage::Put
NEO:    12D7 SYSCALL         [Neo.Storage.GetContext]
        12EF FROMALTSTACK    []
        12F0 DUP             []
        12F1 TOALTSTACK      []
        12F2 PUSHT           []
        12F3 PICKITEM        []
        12F4 FROMALTSTACK    []
        12F5 DUP             []
        12F6 TOALTSTACK      []
        12F7 PUSH5           []
        12F8 PICKITEM        []
        12F9 FROMALTSTACK    []
        12FA DUP             []
        12FB TOALTSTACK      []
        12FC PUSH2           []
        12FD PICKITEM        []
        12FE ADD             []
        12FF NOP             []
        1300 PUSH2           []//swap 0 and 2 param(0)
        1301 XSWAP           []//(0)
        1302 SYSCALL         [Neo.Storage.Put]

打印输出日志

代码语言:javascript
复制
C#:     Transferred(from, to, value);
MSIL:   IL_0124:  callvirt   instance void Neo.SmartContract.ICO_Template/helo::Invoke(uint8[],
                                                                                    uint8[],
                                                                                    valuetype [System.Numerics]System.Numerics.BigInteger)
NEO:    1332 SYSCALL         [Neo.Runtime.Notify]

函数分类

当前使用的版本最常见的就是SYSCALL和CALL_I。

SYSCALL

用于调用外部接口函数,VM定义了一系列的外部接口,接口定义可以在Neo.SmartContract.Framework项目中查看,这些函数实现在Neo项目的SmartContract文件夹下面,函数使用SyscallAttribute标记,合约调用时候会按名索引到对应的执行函数。这里以Storage为例子说明这个问题。

定义
代码语言:javascript
复制
    文件位置:neo-devpack-dotnet\Neo.SmartContract.Framework\Services\Neo\Storage.cs
    public static class Storage
    {
        public static extern StorageContext CurrentContext
        {
            [Syscall("Neo.Storage.GetContext")]
            get;
        }

        [Syscall("Neo.Storage.Get")]
        public static extern byte[] Get(StorageContext context, byte[] key);

        [Syscall("Neo.Storage.Get")]
        public static extern byte[] Get(StorageContext context, string key);

        [Syscall("Neo.Storage.Put")]
        public static extern void Put(StorageContext context, byte[] key, byte[] value);

        [Syscall("Neo.Storage.Put")]
        public static extern void Put(StorageContext context, byte[] key, BigInteger value);

        [Syscall("Neo.Storage.Put")]
        public static extern void Put(StorageContext context, byte[] key, string value);

        [Syscall("Neo.Storage.Put")]
        public static extern void Put(StorageContext context, string key, byte[] value);

        [Syscall("Neo.Storage.Put")]
        public static extern void Put(StorageContext context, string key, BigInteger value);

        [Syscall("Neo.Storage.Put")]
        public static extern void Put(StorageContext context, string key, string value);

        [Syscall("Neo.Storage.Delete")]
        public static extern void Delete(StorageContext context, byte[] key);

        [Syscall("Neo.Storage.Delete")]
        public static extern void Delete(StorageContext context, string key);

        [Syscall("Neo.Storage.Find")]
        public static extern Iterator<byte[], byte[]> Find(StorageContext context, byte[] prefix);

        [Syscall("Neo.Storage.Find")]
        public static extern Iterator<string, byte[]> Find(StorageContext context, string prefix);
    }
实现

StateMachine继承自neo-vm\src\neo-vm\InteropService.cs文件中的InteropService,每次调用Register时,会在其中注册入实现函数,调用时通过名字查找到这个函数,在传入参数执行。

Storage_Put 具体实现

代码语言:javascript
复制
    文件位置:neo\SmartContract\StateMachine.cs 
    private bool Storage_Put(ExecutionEngine engine)
    {
        if (engine.EvaluationStack.Pop() is InteropInterface _interface)
        {
            StorageContext context = _interface.GetInterface<StorageContext>();
            if (context.IsReadOnly) return false;
            if (!CheckStorageContext(context)) return false;
            byte[] key = engine.EvaluationStack.Pop().GetByteArray();
            if (key.Length > 1024) return false;
            byte[] value = engine.EvaluationStack.Pop().GetByteArray();
            storages.GetAndChange(new StorageKey
            {
                ScriptHash = context.ScriptHash,
                Key = key
            }, () => new StorageItem()).Value = value;
            return true;
        }
        return false;
    }

注册函数实现

代码语言:javascript
复制
    Register("System.Storage.Put", Storage_Put);
    Register("System.Storage.Delete", Storage_Delete);

注册函数

代码语言:javascript
复制
    protected void Register(string method, Func<ExecutionEngine, bool> handler)
    {
        dictionary[method] = handler;
    }
转换

转换主要是通过判断函数是否有SyscallAttribute来确定,如果是的会把函数名称及参数信息添加上去。

判断函数

代码语言:javascript
复制
    文件位置:neo-compiler\neon\MSIL\Conv_Multi.cs
    public bool IsSysCall(Mono.Cecil.MethodDefinition defs, out string name)
    {
        if (defs == null)
        {
            name = "";
            return false;
        }
        foreach (var attr in defs.CustomAttributes)
        {
            if (attr.AttributeType.Name == "SyscallAttribute")
            {
                var type = attr.ConstructorArguments[0].Type;
                var value = (string)attr.ConstructorArguments[0].Value;

                //dosth
                name = value;
                return true;



            }
            //if(attr.t)
        }
        name = "";
        return false;
    }

转换Syscall

代码语言:javascript
复制
    var bytes = Encoding.UTF8.GetBytes(callname);
    if (bytes.Length > 252) throw new Exception("string is to long");
    byte[] outbytes = new byte[bytes.Length + 1];
    outbytes[0] = (byte)bytes.Length;
    Array.Copy(bytes, 0, outbytes, 1, bytes.Length);
    //bytes.Prepend 函数在 dotnet framework 4.6 编译不过
    _Convert1by1(VM.OpCode.SYSCALL, null, to, outbytes);
    return 0;
使用
代码语言:javascript
复制
    文件位置:neo-vm\src\neo-vm\ExecutionEngine.cs
    //VM虚拟机执行
    case OpCode.SYSCALL:
    if (!Service.Invoke(Encoding.ASCII.GetString(context.OpReader.ReadVarBytes(252)), this))
        State |= VMState.FAULT;
    break;

    文件位置:neo-vm\src\neo-vm\InteropService.cs
    //
    internal bool Invoke(string method, ExecutionEngine engine)
    {
        if (!dictionary.TryGetValue(method, out Func<ExecutionEngine, bool> func)) return false;
        return func(engine);
    }

CALL_I

用于合约内部函数调用

定义

在合约中自己定义的方法都符合这个类型,如例子中的转账及部署等。

代码语言:javascript
复制
    public static bool NotifyErrorAndReturnFalse(string value)
    {
        Runtime.Notify(value);
        return false;
    }
转换

判断,如果在当前使用的合约机器类库中存在该实现,则确定为这种类型的调用

代码语言:javascript
复制
    else if (this.outModule.mapMethods.ContainsKey(src.tokenMethod))
    {//this is a call
        calltype = 1;
    }

转换

代码语言:javascript
复制
    if (this.outModule.option.useNep8)
    {
        byte _pcount = (byte)defs.Parameters.Count;
        byte _rvcount = (byte)(defs.ReturnType.FullName == "System.Void" ? 0 : 1);

        var c = _Convert1by1(VM.OpCode.CALL_I, null, to, new byte[] { _rvcount, _pcount, 0, 0 });
        c.needfixfunc = true;
        c.srcfunc = src.tokenMethod;

    }
    else
    {
        var c = _Convert1by1(VM.OpCode.CALL, null, to, new byte[] { 5, 0 });
        c.needfixfunc = true;
        c.srcfunc = src.tokenMethod;
    }
    return 0;
使用

这种调用直接跳转到对应的指令位置执行。

代码语言:javascript
复制
    文件位置:neo-vm\src\neo-vm\ExecutionEngine.cs
    case OpCode.CALL:
        InvocationStack.Push(context.Clone());
        context.InstructionPointer += 2;
        ExecuteOp(OpCode.JMP, CurrentContext);
        break;

日志信息

日志提供了一种方式用于我们观察判断合约执行的状态,日志有两种使用方式,一种通过event定义日志,另一种直接调用Neo.Runtime.Notify函数,实质上呢,前者经过一系列的转换步骤后也是转换到Neo.Runtime.Notify逻辑当中,Neo.Runtime.Notify是一种SysCall,最终在执行器中注册如具体的Notify通知实现,因而这里自讨论下event的方式。

定义
代码语言:javascript
复制
    public delegate void transferDelegete(byte[] s1, byte[] s2, BigInteger  num);

    [DisplayName("transfer")]
    public static event transferDelegete Transferred;
转换

因为C#的事件直接执行,实际到MSIL层转换成Invoke调用,其中更多细节可以去研究下C#Delegate,event的具体实现机制,此处不多赘言。

事件解析:解析出来的东西并没啥用,只要在到处json时能看到个事件项目,函数实际上还是去搜索

代码语言:javascript
复制
    文件位置:neo-compiler\neon\MSIL\Converter.cs
    foreach (var e in t.Value.fields)
    {
        if (e.Value.isEvent)
        {
            NeoEvent ae = new NeoEvent();
            ae._namespace = e.Value.field.DeclaringType.FullName;
            ae.name = ae._namespace + "::" + e.Key;
            ae.displayName = e.Value.displayName;
            ae.returntype = e.Value.returntype;
            ae.paramtypes = e.Value.paramtypes;
            outModule.mapEvents[ae.name] = ae;
        }
    }

Invoke查找,之前有提过event和Nottify本质上是相同的,相同之处就体现在IsNotifyCall函数中,该函数会判断函数名称是否是Invoke,类型就粗暴的判断了Action。满足就是个NotifyCall了,返回的函数名就不用在意了,最后转换的时候给统统变成一个名字:Neo.Runtime.Notify。

代码语言:javascript
复制
    文件位置:neo-compiler\neon\MSIL\Conv_Multi.cs
    public bool IsNotifyCall(Mono.Cecil.MethodDefinition defs, Mono.Cecil.MethodReference refs, NeoMethod to, out string name)
    {

        name = to.lastsfieldname;
        if (to.lastsfieldname == null)
            return false;

        Mono.Cecil.TypeDefinition call = null;
        if (defs == null)
        {
            try
            {
                call = refs.DeclaringType.Resolve();
            }
            catch
            {//当不能取得这个,大半都是模板类

            }
        }
        else
        {
            call = defs.DeclaringType;
        }

        if (call != null)
        {
            if (call.BaseType.Name == "MulticastDelegate" || call.BaseType.Name == "Delegate")
            {
                to.lastsfieldname = null;
                return true;
            }
        }
        else//不能还原类型,只好用名字判断了
        {
            if (refs.Name == "Invoke" && refs.DeclaringType.Name.Contains("Action`"))
            {
                to.lastsfieldname = null;
                return true;
            }
        }
        name = "Notify";
        return false;
    }

转换

代码语言:javascript
复制
    //把name参数推进去
    var callp = Encoding.UTF8.GetBytes(callname);
    _ConvertPush(callp, src, to);

    //参数打包成array
    _ConvertPush(pcount + 1, null, to);
    _Convert1by1(VM.OpCode.PACK, null, to);

    //a syscall
    {
        var bytes = Encoding.UTF8.GetBytes("Neo.Runtime.Notify");
        byte[] outbytes = new byte[bytes.Length + 1];
        outbytes[0] = (byte)bytes.Length;
        Array.Copy(bytes, 0, outbytes, 1, bytes.Length);
        //bytes.Prepend 函数在 dotnet framework 4.6 编译不过
        _Convert1by1(VM.OpCode.SYSCALL, null, to, outbytes);
    }

Neo.Runtime.Notify 定义

代码语言:javascript
复制
    文件位置:neo-devpack-dotnet\Neo.SmartContract.Framework\Services\Neo\Runtime.cs
    public static class Runtime
    {
        public static extern TriggerType Trigger
        {
            [Syscall("Neo.Runtime.GetTrigger")]
            get;
        }

        public static extern uint Time
        {
            [Syscall("Neo.Runtime.GetTime")]
            get;
        }

        [Syscall("Neo.Runtime.CheckWitness")]
        public static extern bool CheckWitness(byte[] hashOrPubkey);

        [Syscall("Neo.Runtime.Notify")]
        public static extern void Notify(params object[] state);

        [Syscall("Neo.Runtime.Log")]
        public static extern void Log(string message);
    }
使用

c#中调用

代码语言:javascript
复制
    Transferred(null, Owner, total_amount);

Vm执行Neo.Runtime.Notify Syscall.

代码语言:javascript
复制
    文件位置:neo\SmartContract\StateReader.cs
    protected virtual bool Runtime_Notify(ExecutionEngine engine)
    {
        StackItem state = engine.EvaluationStack.Pop();
        NotifyEventArgs notification = new NotifyEventArgs(engine.ScriptContainer, new UInt160(engine.CurrentContext.ScriptHash), state);
        Notify?.Invoke(this, notification);
        notifications.Add(notification);
        return true;
    }

数据存储

Neo的数据存储主要通过Storage接口提供,外部实现的数据库存储,具体参考上面给的代码例子,Neo合约也不支持普通成员变量,但是静态成员是支持的,原因在于,静态成员编译即确定,在转换的过程中会在每个使用到静态变量的地方嵌入实际的值。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/08/10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • NEO C# 合约编译器原理解析
    • 原理
      • 代码生成
        • c# -> MSIL
        • MSIL -> 合约字节码
      • 代码调用
        • 部署合约函数流程
        • 转账合约函数调转逻辑
        • 函数分类
        • SYSCALL
        • CALL_I
      • 日志信息
        • 数据存储
        相关产品与服务
        数据保险箱
        数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档