一、啰嗦两句

昨天讲了智能合约的一生,那丫长啥样啊?今儿我就跟各位唠叨唠叨。

二、一个简单的智能合约

下面这段就是NEO实例源码里的一个,干撒用的?聪明的你一眼儿就看出来了吧,就是一个所谓域名合约的增删改查。有几点我唠叨两句

using Neo.SmartContract.Framework.Services.Neo;

namespace Neo.SmartContract
{
public class Domain : Framework.SmartContract
{
public static object Main(string operation, params object[] args)
{
switch (operation)
{
case "query":
return Query((string)args[]);
case "register":
return Register((string)args[], (byte[])args[]);
case "transfer":
return Transfer((string)args[], (byte[])args[]);
case "delete":
return Delete((string)args[]);
default:
return false;
}
} private static byte[] Query(string domain)
{
return Storage.Get(Storage.CurrentContext, domain);
} private static bool Register(string domain, byte[] owner)
{
if (!Runtime.CheckWitness(owner)) return false;
byte[] value = Storage.Get(Storage.CurrentContext, domain);
if (value != null) return false;
Storage.Put(Storage.CurrentContext, domain, owner);
return true;
} private static bool Transfer(string domain, byte[] to)
{
if (!Runtime.CheckWitness(to)) return false;
byte[] from = Storage.Get(Storage.CurrentContext, domain);
if (from == null) return false;
if (!Runtime.CheckWitness(from)) return false;
Storage.Put(Storage.CurrentContext, domain, to);
return true;
} private static bool Delete(string domain)
{
byte[] owner = Storage.Get(Storage.CurrentContext, domain);
if (owner == null) return false;
if (!Runtime.CheckWitness(owner)) return false;
Storage.Delete(Storage.CurrentContext, domain);
return true;
}
}
}

1. 上一节讲了,一个智能合约就是继承自SmartContract的类,Main函数啊,方法啊,全得是静态的,因为NEO的编译器就认静态的。

2. Main就是智能合约的入口,调用的时候会穿些参数,第一个就是opeartion,根据这个来判断是啥操作,这点和Fabric很像,就一个init一个invoke,Etherenum不是这样的。

3. 逻辑都能看明白,这个Storage是个啥玩意,看上去像个存储,在哪存储?这不就是serverless吗?ok,咱就以此为突破,重点关注一下这个Storage。

源码说话。这个Storage是NEO工具包(SmartContract那个类一个项目下的)里的一个类,我们看下源码。

using System.Numerics;

namespace Neo.SmartContract.Framework.Services.Neo
{
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);
}
}

我把其他方法都删了,留一个Get方法,示意一下。看到这,是不是有点懵逼,SysCall什么鬼,这种写法是不是似曾相识?是不是和dllimport差不多?其实我琢磨着作者写的时候也有这么个意图,就说啊,这是一系统调用啊,调用咱系统的东西。那到底这玩意儿咋个原理,咱们就得看NEO的编译器源码了。上一节咱提了,NEO的编译器就是根据规则把对应的代码翻译成指令码,编译器这部分咱后面也要说,找源码的过程比较琐碎,不贴代码了,这里先理解成编译器把他编译成OpCode.SYSCALL Neo.Storage.Get,就是系统调用Neo.Storage.Get。下面的问题就是NEO的虚拟机该怎么解释这个指令了,我们再去NEO.VM项目里找结果。

private readonly InteropService service;

            case OpCode.SYSCALL:
if (!service.Invoke(Encoding.ASCII.GetString(context.OpReader.ReadVarBytes()), this))
State |= VMState.FAULT;
break;

再来看看Interopservice里Invoke都干了些啥,也是删除了部分代码。

using System;
using System.Collections.Generic; namespace Neo.VM
{
public class InteropService
{
private Dictionary<string, Func<ExecutionEngine, bool>> dictionary = new Dictionary<string, Func<ExecutionEngine, bool>>(); public InteropService()
{
Register("System.ExecutionEngine.GetScriptContainer", GetScriptContainer);
Register("System.ExecutionEngine.GetExecutingScriptHash", GetExecutingScriptHash);
Register("System.ExecutionEngine.GetCallingScriptHash", GetCallingScriptHash);
Register("System.ExecutionEngine.GetEntryScriptHash", GetEntryScriptHash);
} protected void Register(string method, Func<ExecutionEngine, bool> handler)
{
dictionary[method] = handler;
} internal bool Invoke(string method, ExecutionEngine engine)
{
if (!dictionary.ContainsKey(method)) return false;
return dictionary[method](engine);
}
}
}

看起来InteropService里保留了一个字段,根据不同的方法名,注册不同的执行方法,我们要找的Neo.Storage.Get这个方法key是在那里注册的呢?搜。  

namespace Neo.SmartContract
{
public class StateReader : InteropService
{
public event EventHandler<NotifyEventArgs> Notify;
public event EventHandler<LogEventArgs> Log; public static readonly StateReader Default = new StateReader(); public StateReader()
{
Register("Neo.Storage.Get", Storage_Get);
} protected virtual bool Storage_Get(ExecutionEngine engine)
{
StorageContext context = engine.EvaluationStack.Pop().GetInterface<StorageContext>();
ContractState contract = Blockchain.Default.GetContract(context.ScriptHash);
if (contract == null) return false;
if (!contract.HasStorage) return false;
byte[] key = engine.EvaluationStack.Pop().GetByteArray();
StorageItem item = Blockchain.Default.GetStorageItem(new StorageKey
{
ScriptHash = context.ScriptHash,
Key = key
});
engine.EvaluationStack.Push(item?.Value ?? new byte[]);
return true;
}
}
}

注意到Blockchain.Default.GetstorageItem()这个方法了吧,虚拟机执行器把链上的数据取出来了,这个Blockchain的实现是leveldb这个咱也后面再讲。

好啦,到现在这一圈可以理解智能合约的执行过程了吧。聪明的你也一定发现了,你看的懂的那些逻辑,也会被NEO的编译器编译成指令码,这部分就复杂咯,后面咱们讲编译器的时候详细的说,编译器这块还是挺复杂的,面向代码作者拜一拜。。。

三、小结

智能合约好写,很容易理解,但是从头撸到底才能透彻的知道了解它的运行原理,撸的过程略过了很多东西,聪明的你一定很好奇吧,别着急,咱们下回书,再说。

NEO从入门到开窗(2) - 智能合约的面相的更多相关文章

  1. NEO从入门到开窗(1) - 一个智能合约的诞生

    一.啰嗦两句 最近一直都在研究区块链,BitCoin,Etherenum, Hyper Ledger Fabric还有今天的主角小蚂蚁,当然出名以后改了一个艺名叫NEO.区块链大部分都是用Golang ...

  2. NEO从入门到开窗(3) - NEO编译器

    一.啰嗦两句 第一节的时候咱说了C#编译完了之后,就该NEO的编译器搞事情了.我们完全可以按这个节奏搞,手动用NEO的编译器neon编译dll文件生成指令码文件.avm.但是NEO团队给我们写智能合约 ...

  3. NEO从入门到开窗(4) - NEO CLI

    一.唠叨两句 首先,我们都知道区块链是去中心化的,其中节点都是对等节点,每个节点都几乎有完整的区块链特性,CLI就是NEO的一个命令行对等节点,当然也有GUI这个项目,图形化的NEO节点.节点之间需要 ...

  4. NEO智能合约开发(二)再续不可能的任务

      NEO智能合约开发中,应用合约比较简单,是的你没看错,应用合约比较简单. 应用合约三部曲,发布.调用.看结果.除了看结果工具比较缺乏,发布调用neogui最起码可以支撑你测试.   鉴权合约比较麻 ...

  5. BOOM -- 智能合约编程

    译注:原文首发于ConsenSys开发者博客,原作者为Eva以及ConsenSys的开发团队.如果您想要获取更多及时信息,可以访问ConsenSys首页点击左下角Newsletter订阅邮件.本文的翻 ...

  6. NEO智能合约开发(一)不可能完成的任务

    悬赏任务 兹有如下合约 public static object Main(string method, object[] args) { if (Runtime.Trigger == Trigger ...

  7. 五一劳动节,讲讲NEO智能合约的调试

    之前我们说过NEO智能合约的调试问题,过去了一段时间,有很多东西都发生了比较大的变化.让我们重新再来探讨一下这个话题. 先说日期,2018年4月27日,马上迎来劳动节.   以后可能还会再次谈论这个话 ...

  8. 以太坊智能合约开发,Web3.js API 中文文档 ethereum web3.js入门说明

    以太坊智能合约开发,Web3.js API 中文文档 ethereum web3.js入门说明 为了让你的Ðapp运行上以太坊,一种选择是使用web3.js library提供的web3.对象.底层实 ...

  9. 用 C# 编写 NEO 智能合约

    工具 -> 扩展和更新安装 NeoContractPlugin 插件 打开 Visual Studio 2017,打开 工具, 扩展和更新 ,在左侧点击 联机 ,搜索 Neo,安装 NeoCon ...

随机推荐

  1. PAT1116. Come on! Let's C (map)

    思路:模拟一下就好了,map用来记录每个人的排名. AC代码 #include <stdio.h> #include <map> #include <math.h> ...

  2. 【BZOJ2959】长跑 (LCT+并查集)

    Time Limit: 1000 ms   Memory Limit: 256 MB Description 某校开展了同学们喜闻乐见的阳光长跑活动.为了能“为祖国健康工作五十年”,同学们纷纷离开寝室 ...

  3. foo的出现

    在计算机程序设计与计算机技术的相关文档中,术语foobar是一个常见的无名氏化名,常被作为“伪变量”使用. 从技术上讲,“foobar”很可能在1960年代至1970年代初通过迪吉多的系统手册传播开来 ...

  4. requests+多进程poll+pymongo实现抓取小说

    今天看着有个很吸引人的小说作品信息:一家只在深夜开门营业的书屋,欢迎您的光临.作为东野奎吾<深夜食堂>漫画的fans,看到这个标题按捺不住我的好奇心........ 所以我又抓下来了,总共 ...

  5. javascript-深入理解&&和||

    先从两个问题看起: 第一个问题 为什么 a && b 返回的是true,b && a 返回的是6 var user = 6; var both = true; cons ...

  6. 胖虎都看得懂的CSS入门

    CSS入门 CSS是什么 摘自维基百科 层叠样式表(英语:Cascading Style Sheets,简写CSS),又称串样式列表.级联样式表.串接样式表.层叠样式表.階層式樣式表,一种用来为结构化 ...

  7. Java StringBuilder 和 StringBuffer 源码分析

    简介 StringBuilder与StringBuffer是两个常用的操作字符串的类.大家都知道,StringBuilder是线程不安全的,而StringBuffer是线程安全的.前者是JDK1.5加 ...

  8. [linux]device eth0 does not seem to be present, delaying initialization

    mlite虚拟机启动出错,就把这个虚拟机删除掉重新建立,系统虚拟硬盘使用之前的,启动系统后不能上网,通过ifconfig查看网卡没启动,遂启动网卡服务,但是出错,就是:device eth0 does ...

  9. Solution for link error:Cannot Open File 'python27_d.lib'

    引自:http://guangboo.org/2013/01/17/solution-link-errorcannot-open-file-python27_dlib 感谢原作者 使用C调用Pytho ...

  10. AM335x关于LCD屏幕的时钟PLL配置

    主要参考的是AM335x的TRM的第8章PRCM模块和13章LCD Controller. 这里在LCD Controller里面的配置描述的比较详细了,分频和像素.消影值的设置等等.不在赘述,很多人 ...