文档章节

NEO智能合约之发布和升级(二)

红烧飞鱼
 红烧飞鱼
发布于 06/25 02:04
字数 1594
阅读 25
收藏 0
点赞 0
评论 0
EAC

接NEO智能合约之发布和升级(一),我们接下来说说智能合约的升级功能。

一    准备工作

        合约的升级需要在合约内预先设置好升级接口,以方便在升级时调用。接下来我们对NEO智能合约之发布和升级(一)中的合约例子进行改造,添加升级接口。并发布合约得到合约的hash(0x8c4994ccf1c123f91090d07568653e54d74f307d),调用put方法在存储区存入值。

using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Services.Neo;
using Neo.SmartContract.Framework.Services.System;
using Helper = Neo.SmartContract.Framework.Helper;
using System;
using System.ComponentModel;
using System.Numerics;

namespace NeoContract1
{
    public class Contract1 : SmartContract
    {
        static readonly byte[] superAdmin = Helper.ToScriptHash("ALjSnMZidJqd18iQaoCgFun6iqWRm2cVtj");//管理员

        public static object Main(string method, object[] args)
        {
            var magicstr = "NEL";

            if (Runtime.Trigger == TriggerType.Verification)//取钱才会涉及这里
            {
                return true;
            }

            else if (Runtime.Trigger == TriggerType.VerificationR)//取钱才会涉及这里
            {
                return true;
            }
            else if (Runtime.Trigger == TriggerType.Application)
            {
                if (method == "put")
                {
                    Storage.Put(Storage.CurrentContext, "put","1");
                    return true;
                }
                if (method == "get")
                {
                    return Storage.Get(Storage.CurrentContext, "put");
                }


                if (method == "upgrade")//合约的升级就是在合约中要添加这段代码来实现
                {
                    //不是管理员 不能操作
                    if (!Runtime.CheckWitness(superAdmin))
                        return false;

                    if (args.Length != 1 && args.Length != 9)
                        return false;

                    byte[] script = Blockchain.GetContract(ExecutionEngine.ExecutingScriptHash).Script;
                    byte[] new_script = (byte[])args[0];
                    //如果传入的脚本一样 不继续操作
                    if (script == new_script)
                        return false;

                    byte[] parameter_list = new byte[] { 0x07, 0x10 };
                    byte return_type = 0x05;
                    bool need_storage = (bool)(object)05;
                    string name = "test";
                    string version = "1.1";
                    string author = "NEL";
                    string email = "0";
                    string description = "test";

                    if (args.Length == 9)
                    {
                        parameter_list = (byte[])args[1];
                        return_type = (byte)args[2];
                        need_storage = (bool)args[3];
                        name = (string)args[4];
                        version = (string)args[5];
                        author = (string)args[6];
                        email = (string)args[7];
                        description = (string)args[8];
                    }
                    Contract.Migrate(new_script, parameter_list, return_type, need_storage, name, version, author, email, description);
                    return true;
                }

            }
            return false;
        }
    }
}

        代码中我们添加了upgrade的方法用以合约升级。在升级方法中,我们需要验证权限以确保安全性,然后就可以调用升级函数进行合约的升级。合约升级之后,原合约会被销毁,存储区会被移到新的合约。

二    利用thinwallet升级合约

    在发布上面的合约之后,我想增加一个delete功能,来删除某个存储。于是我对原合约进行修改,添加了delete方法。重新编译,得到新的合约,hash(0x53ab4dfdae199b8d76f0eac8363fb07e652aef1f)。

using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Services.Neo;
using Neo.SmartContract.Framework.Services.System;
using Helper = Neo.SmartContract.Framework.Helper;
using System;
using System.ComponentModel;
using System.Numerics;

namespace NeoContract1
{
    public class Contract1 : SmartContract
    {
        static readonly byte[] superAdmin = Helper.ToScriptHash("ALjSnMZidJqd18iQaoCgFun6iqWRm2cVtj");//管理员

        public static object Main(string method, object[] args)
        {
            var magicstr = "NEL";

            if (Runtime.Trigger == TriggerType.Verification)//取钱才会涉及这里
            {
                return true;
            }

            else if (Runtime.Trigger == TriggerType.VerificationR)//取钱才会涉及这里
            {
                return true;
            }
            else if (Runtime.Trigger == TriggerType.Application)
            {
                if (method == "put")
                {
                    Storage.Put(Storage.CurrentContext, "put","1");
                    return true;
                }
                if (method == "get")
                {
                    return Storage.Get(Storage.CurrentContext, "put");
                }
                if (method == "delete")
                {
                    Storage.Delete(Storage.CurrentContext, "put");
                }
                if (method == "upgrade")
                {
                    //不是管理员 不能操作
                    if (!Runtime.CheckWitness(superAdmin))
                        return false;

                    if (args.Length != 1 && args.Length != 9)
                        return false;

                    byte[] script = Blockchain.GetContract(ExecutionEngine.ExecutingScriptHash).Script;
                    byte[] new_script = (byte[])args[0];
                    //如果传入的脚本一样 不继续操作
                    if (script == new_script)
                        return false;

                    byte[] parameter_list = new byte[] { 0x07, 0x10 };
                    byte return_type = 0x05;
                    bool need_storage = (bool)(object)05;
                    string name = "test";
                    string version = "1.1";
                    string author = "NEL";
                    string email = "0";
                    string description = "test";

                    if (args.Length == 9)
                    {
                        parameter_list = (byte[])args[1];
                        return_type = (byte)args[2];
                        need_storage = (bool)args[3];
                        name = (string)args[4];
                        version = (string)args[5];
                        author = (string)args[6];
                        email = (string)args[7];
                        description = (string)args[8];
                    }
                    Contract.Migrate(new_script, parameter_list, return_type, need_storage, name, version, author, email, description);
                    return true;
                }

            }
            return false;
        }
    }
}

因为我想保留原合约的存储区,所以我用升级功能来升级合约。

打开thinwallet,点击Upgrade Sc(升级合约按钮),出现如下页面,填入相关数据。

点击确认回到主页面,点击test按钮。你会发现test之后返回的状态是Fault,执行失败。那是因为在升级合约里,我们验证了调用者的权限,invoke调用并没有签名这一步。所以我们需要自己在output里自己添加一条丢弃掉。费用自己估算。

点击发送交易得到交易id,等待交易确认。

交易确认后我们AppCall原合约(0x8c4994ccf1c123f91090d07568653e54d74f307d),发现合约不存在。

接下来我们AppCall新合约(0x53ab4dfdae199b8d76f0eac8363fb07e652aef1f),发现合约存在,不调用put,直接调用get看是否能获取到值。

如下图,我们在没有调用put设置值的情况下还是get到了数据。说明存储区被新的合约所继承。

 

三    升级合约的代码介绍

        升级合约本质上就是调用原合约的升级函数来进行升级。调用Contract.Migrate方法,参数和create相同。这里就不重复介绍了,详情见NEO智能合约之发布和升级(一)。

        升级合约的构造代码如下

ThinNeo.ScriptBuilder sb = new ThinNeo.ScriptBuilder();
//倒叙插入数据
var array = new MyJson.JsonNode_Array();
array.AddArrayValue("(bytes)" + str_script);//新的合约代码
array.AddArrayValue("(bytes)0710");
array.AddArrayValue("(bytes)05");
array.AddArrayValue("(int)"+ 5);
array.AddArrayValue("(str)合约测试");//name
array.AddArrayValue("(str)1");//version
array.AddArrayValue("(str)ss");//author
array.AddArrayValue("(str)1");//email
array.AddArrayValue("(str)sssss");//desc
sb.EmitParamJson(array);//参数倒序入
sb.EmitParamJson(new MyJson.JsonNode_ValueString("(str)upgrade"));
var shash = Config.dapp_sgas; //原合约hash
sb.EmitAppCall(shash);

         最后构造交易数据  下图中的makeTran是对tran的inputs和outputs进行构造

ThinNeo.InvokeTransData extdata = new ThinNeo.InvokeTransData();
extdata.gas = 500;// Math.Ceiling(gas_consumed - 10);
extdata.script = sb.ToArray();

//拼装交易体
ThinNeo.Transaction tran = Helper.makeTran(dir[Config.id_GAS], null, new ThinNeo.Hash256(Config.id_GAS), extdata.gas);
tran.version = 1;
tran.extdata = extdata;
tran.type = ThinNeo.TransactionType.InvocationTransaction;
byte[] msg = tran.GetMessage();
byte[] signdata = ThinNeo.Helper.Sign(msg, prikey);
tran.AddWitness(signdata, pubkey, address);
string txid = tran.GetHash().ToString();
byte[] data = tran.GetRawData();
string rawdata = ThinNeo.Helper.Bytes2HexString(data);
url = Helper.MakeRpcUrlPost(Config.api_local, "sendrawtransaction", out postdata, new MyJson.JsonNode_ValueString(rawdata));
result = await Helper.HttpPost(url, postdata);
        ThinNeo.Transaction makeTran(Dictionary<string, List<Utxo>> dir_utxos, string targetaddr, ThinNeo.Hash256 assetid, decimal sendcount)
        {
            if (!dir_utxos.ContainsKey(assetid.ToString()))
                throw new Exception("no enough money.");

            List<Utxo> utxos = dir_utxos[assetid.ToString()];
            var tran = new ThinNeo.Transaction();
            tran.type = ThinNeo.TransactionType.ContractTransaction;
            tran.version = 0;//0 or 1
            tran.extdata = null;

            tran.attributes = new ThinNeo.Attribute[0];
            var scraddr = "";
            utxos.Sort((a, b) =>
            {
                if (a.value > b.value)
                    return 1;
                else if (a.value < b.value)
                    return -1;
                else
                    return 0;
            });
            decimal count = decimal.Zero;
            List<ThinNeo.TransactionInput> list_inputs = new List<ThinNeo.TransactionInput>();
            for (var i = 0; i < utxos.Count; i++)
            {
                ThinNeo.TransactionInput input = new ThinNeo.TransactionInput();
                input.hash = utxos[i].txid;
                input.index = (ushort)utxos[i].n;
                list_inputs.Add(input);
                count += utxos[i].value;
                scraddr = utxos[i].addr;
                if (count >= sendcount)
                {
                    break;
                }
            }
            tran.inputs = list_inputs.ToArray();
            if (count >= sendcount)//输入大于等于输出
            {
                List<ThinNeo.TransactionOutput> list_outputs = new List<ThinNeo.TransactionOutput>();
                //输出
                if (sendcount > decimal.Zero && targetaddr != null)
                {
                    ThinNeo.TransactionOutput output = new ThinNeo.TransactionOutput();
                    output.assetId = assetid;
                    output.value = sendcount;
                    output.toAddress = ThinNeo.Helper.GetPublicKeyHashFromAddress(targetaddr);
                    list_outputs.Add(output);
                }

                //找零
                var change = count - sendcount;
                if (change > decimal.Zero)
                {
                    ThinNeo.TransactionOutput outputchange = new ThinNeo.TransactionOutput();
                    outputchange.toAddress = ThinNeo.Helper.GetPublicKeyHashFromAddress(scraddr);
                    outputchange.value = change;
                    outputchange.assetId = assetid;
                    list_outputs.Add(outputchange);

                }
                tran.outputs = list_outputs.ToArray();
            }
            else
            {
                throw new Exception("no enough money.");
            }
            return tran;
        }

        其中所用到的构造脚本的scriptBuilder和构造交易的Transaction都是用了李总写的sdk。如果你要用原生的Transaction和ScriptBuilder,这里就不附上代码了。原理一样,自己对比。

 

 

thinwallet    https://github.com/NewEconoLab/neo-thinsdk-cs    thinWallet工程

sdk for neo (c#)     https://github.com/NewEconoLab/neo-thinsdk-cs    thinSDK工程

文中的例子  https://github.com/NewEconoLab/neo-thinsdk-cs/blob/master/smartContractDemo/tests/others/MigrateScDemo.cs

© 著作权归作者所有

共有 人打赏支持
红烧飞鱼
粉丝 1
博文 2
码字总数 3230
作品 0
让分叉成为历史?一个区块链世界的新物种

区块链技术如今正在经历快速变革,涌现出了像以太坊、EOS、NEO、Ripple、IOTA等热点项目。不过目前圈内很多讨论仍然围绕在如何在不妨碍创新和去中心化的前提下减少波动性。作为小蚁(NEO)的...

雪花又一年
04/23
0
0
盘点国内最热门的五款区块链项目

在科技迅猛发展的今天,科学技术的发展就更显得尤为重要。不过,技术的存在,不单单只象征着一种开发的工具,它更多的是象征着促进人类社会变革的一个手段。 2009年,由中本聪一手创办的“比...

未来财经
2017/12/13
0
0
仅支持BCH的众筹平台Coinfundr或能革新众筹业

在大众创业、万众创新的时代背景下,众筹为国人的创意和创造提供了无限可能。相对于传统的融资方式,众筹更为开放,且依靠大众力量,更注重创意特质,创作不再受投资人左右,本质上也是一种去...

lpy411
05/15
0
0
“瀑布期”普遍跌落,还有这5款数字货币屹立不倒!

随着2017年尾一波流的“瀑布期”,数字货币普遍跌落,甚至有的数字货币有大跌迹象。此前,比特币曾单价接近12万,不少数字货币的投资者,纷纷感慨,持有者觉得持有的太少,没有的只能感叹错失...

未来财经
01/16
0
0
大行情下频繁上涨的3款数字货币,你选中了吗?

去年末尾,币圈真正可谓是“一波三折”,几轮“瀑布”,没有哪个韭菜可以于瀑布中干着走出来。但是凡事都是要辩证看待的,既然有跌,自会有涨。 年后三款数字货币,涨势还是很迅猛的,不知道...

未来财经
02/27
0
0
「镁客·请讲」MATRIX张国强:不惧公链竞争,将使用AI技术夯实区块链地基

预计到10月1日,MATRIX的主链会上线。 在电影《黑客帝国》中,MATRIX是一套人工智能程序,它类似于一个巨大的网络,连接着无数人的意识。 在数学名词中,MATRIX是矩阵的意思,它常常被用来表...

行者武松
03/15
0
0
Zeppelin:用于区块链应用的开源安全智能合约架构

9月15日,Zeppelin的路线图建议发布。Zeppelin是一种构建安全智能合约的开源架构,遵循MIT许可。该建议的推出正是时候,从DevCon2大会上围绕着智能合约形式验证的报告和讨论的次数上就可以证...

雪花又一年
04/19
0
0
AOS:引领区块链3.0时代,构建价值生态

区块链技术平台是一切未来区块链商业应用的基础设施,在目前已有的技术,如共识机制、智能合约、跨链技术、侧链技术、兼容性和扩展性等的组合影响下,直接决定了区块链平台的基本性能。 围绕...

链世界
前天
0
0
区块链主链——2018年公链发展元年

● 公链平台主要定位为区块链操作系统,为各种应用开发提供基础技术支撑,是未来区块链技术落地应用的核心基础;本报告主要针对已经公开披露技术白皮书的33个项目进行研究,针对技术方案、开...

小本聪
今天
0
0
智能合约类代币EOS、BCH、Tezos很有可能会超越BTC

作者区块链卡咩 卡咩最近看到一个趋势,那就是智能合约类的代币很有可能在不久的将来,在市值上超过BTC,并且会逐渐替代掉BTC,作为法币更有力的竞争者。当然,这个趋势的前提是BTC一直维持当...

lpy411
05/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

崛起于Springboot2.X之集成MongoDb使用mongoTemplate CRUD(27)

1、pom依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version></dependency><dependency> <groupId>log4j</......

木九天
10分钟前
0
0
切分log日志

新建logback.xml放到resource里面 <?xml version="1.0" encoding="utf-8"?><configuration> <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender"> <......

talen
15分钟前
0
0
spring @Resource 和 @Autowired 的使用区别

这两个 注解 @Resource 和 @Autowired , 常识都知道 @Resource 是 JAVAEE 自带的,@Autowired 是 spring 的自定义注解。 一般情况下, 使用 bean的时候, 这两个注解 随便使用一个即可。 但...

之渊
20分钟前
0
0
springboot集成elasticsearch客户端问题记录

1背景说明 服务端ES版本为5.5.2,springboot版本为1.5.6。 工程中添加如下依赖 2问题记录 2.1 NetworkPlugin类找不到 报错java.lang.ClassNotFoundException: org.elasticsearch.plugins.Net...

zjg23
22分钟前
1
0
快速构建ceph可视化监控系统

前言 ceph的可视化方案很多,本篇介绍的是比较简单的一种方式,并且对包都进行了二次封装,所以能够在极短的时间内构建出一个可视化的监控系统 本系统组件如下: ceph-jewel版本 ceph_expor...

万建宁
22分钟前
0
0
Java构造器使用注意

public class 父类A {int age = 10;protected void say() {System.out.println("父类A");}public 父类A() {override();}public void override() {Syst...

咸鱼AI
23分钟前
0
0
TensorFlow 线性分类

构造直线 z = 2 * x - 3 * y + 4 x0*w0+x1*w1+b=0 x1=-x0* w0/w1-b/w1 斜率 k= -w0/w1 截距 -b/w1 随机生成数据,加入一定的偏差,用直线将二维平面分为两部分 使用线性模型拟合参数 损失函数...

阿豪boy
26分钟前
0
0
翻译冒泡排序测试

翻译一个冒泡排序: var a = [1,3,2,4,6,5];var f = 0;var n = a.length ;for( var i =1; i<= n; i++) { for( var j = n-1 ; j >= i; j --) { if(a[j] < a[j+1]) { ......

钟元OSS
27分钟前
0
0
maven父、子级版本号同时修改

命令: mvn versions:set -DnewVersion=0.0.2-SNAPSHOT

沉默的懒猫
29分钟前
0
0
Spring boot中的异常处理之注解响应

Controller层 return patientRepository.findById(id) .orElseThrow(() -> new NotFoundException(String.format("Patient %d not found", id))); Exception类 @ResponseS......

亚林瓜子
29分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部