当前位置: 首页 > 编程日记 > 正文

深入浅出谈以太坊智能合约

链客,专为开发者而生,有问必答!

此文章来自区块链技术社区,未经允许拒绝转载。
在这里插入图片描述
1什么是合约?

合约是代码(它的功能)和数据(它的状态)的集合,存在于以太坊区块链的特定地址。 合约账户能够在彼此之间传递信息,进行图灵完备的运算。合约依靠被称作以太坊虚拟机(EVM) 字节代码(以太坊特有的二进制格式)上的区块链运行。

合约很典型地用诸如Solidity等高级语言写成,然后编译成字节代码上传到区块链上。

也有其他语言可以用于编写智能合约如Serpent和LLL,在下一节会进一步阐述。去中心化应用开发资源列出了综合的开发环境,帮助你用这些语言开发的开发者工具,提供测试和部署支持等功能。

2以太坊高级语言

合约依靠被称作以太坊虚拟机(EVM) 字节代码(以太坊特有的二进制格式)上的区块链运行。然而,合约是很典型地用诸如Solidity等高级语言写成的,它会用以太坊虚拟机编译器编译成字节代码上传到区块链。

下面是开发者可以用来为以太坊写智能合约的高级语言。

  1. Solidity

Solidity是和JavaScript相似的语言,你可以用它来开发合约并编译成以太坊虚拟机字节代码。它目前是以太坊最受欢迎的语言。

  1. Serpent

Serpent是和Python类似的语言,可以用于开发合约编译成以太坊虚拟机字节代码。它力求简洁, 将低级语言在效率方面的优点和编程风格的操作简易相结合,同时合约编程增加了独特的领域特定功能。Serpent用LLL编译。

  1. LLL

Lisp Like Language (LLL)是和Assembly类似的低级语言。它追求极简;本质上只是直接对以太坊虚拟机的一点包装。

  1. Mutan (弃用)

Mutan是个静态类型,由Jeffrey Wilcke 开发设计的C类语言。它已经不再受到维护。

3写合约

没有Hello World程序,语言就不完整。Solidity在以太坊环境内操作,没有明显的“输出”字符串的方式。我们能做的最接近的事就是用日志记录事件来把字符串放进区块链,示例如下:

contract HelloWorld {

event Print(string out);

function() { Print(“Hello, World!”); }

}

每次执行时,这个合约都会在区块链创建一个日志入口,印着“Hello,World!”参数。

另请参阅:Solidity docs里有更多写Solidity代码的示例和指导。

4编译合约

solidity合约的编译可以通过很多机制完成。

通过命令行使用solc编译器实现。
在geth或eth提供的javascript控制台使用web3.eth.compile.solidity (这仍然需要安装solc 编译器)实现。
通过在线Solidity实时编译器实现。
通过建立solidity合约的Meteor dapp Cosmo实现。
通过Mix IDE实现。
通过以太坊钱包实现。
注意:关于solc和编译Solidity合约代码的更多信息可在此查看。

  1. 在geth设置solidity编译器

如果你启动了geth节点,就可以查看哪个编译器可用。示例如下:

web3.eth.getCompilers();

[“lll”, “solidity”, “serpent”]

这一指令会返回到显示当前哪个编译器可用的字符串。

注意:solc编译器和cpp- ethereum一起安装。或者,你可以自己创建。

如果你的solc可执行文件不在标准位置,可以用—solc标志为solc可执行文件指定一个定制路线。示例如下:

$ geth --solc /usr/local/bin/solc

或者你可以通过控制台在执行期间设置这个选项:

admin.setSolc("/usr/local/bin/solc")

solc, the solidity compiler commandline interface

Version: 0.2.2-02bb315d/.-Darwin/appleclang/JIT linked to libethereum-1.2.0-8007cef0/.-Darwin/appleclang/JIT

path: /usr/local/bin/solc

  1. 编译一个简单合约

让我们来编译一个简单的合约源,示例如下:

source = “contract test { function multiply(uint a) returns(uint d) { return a * 7; } }”

这个合约提供了一个单一方法multiply,它和一个正整数a调用并返回到a*7。

下面准备在geth JS控制台用eth.compile.solidity()编译solidity代码:

contract = eth.compile.solidity(source).test

{

code: ‘605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056’,

info: {

language: ‘Solidity’,

languageVersion: ‘0’,

compilerVersion: ‘0.9.13’,

abiDefinition: [{

constant: false,

inputs: [{

name: ‘a’,

type: ‘uint256’

} ],

name: ‘multiply’,

outputs: [{

name: ‘d’,

type: ‘uint256’

} ],

type: ‘function’

} ],

userDoc: {

methods: {

}

},

developerDoc: {

methods: {

}

},

source: 'contract test { function multiply(uint a) returns(uint d) { return a

7; } }’

}

}

注意:编译器通过RPC因此也能通过web3.js,对浏览器内任何通过RPC/IPC连接到geth的Ðapp可用。

下面的例子会向你展示如何通过JSON-RPC接合geth来使用编译器。

$ geth --datadir ~/eth/ --loglevel 6 --logtostderr=true --rpc --rpcport 8100 --rpccorsdomain ’ * ’ --mine console 2>> ~/eth/eth.log

$ curl -X POST --data '{“jsonrpc”:“2.0”,“method”:“eth_compileSolidity”,“params”:["contract test {

单源编译器输出会给出你合约对象,每个都代表一个单独的合约。eth.compile.solidity 的实际返还值是合约名字到合约对象的映射。由于合约名字是test,eth.compile.solidity(source).test会给出包含下列领域的测试合约对:

Code:编译的以太坊虚拟机字节代码。
Info:从编译器输出的额外元数据。
Source:源代码。
Language:合约语言 (Solidity,Serpent,LLL)。
LanguageVersion:合约语言版本。
compilerVersion:用于编译这个合约的solidity编译器版本。
abiDefinition:应用的二进制界面定义。
userDoc:用户的NatSpec Doc。
developerDoc:开发者的NatSpec Doc。
编译器输出的直接结构化(到code和info)反映了两种非常不同的部署路径。编译的以太坊虚拟机代码和一个合约创建交易被发送到区块,剩下的(info)在理想状态下会存活在去中心化云上,公开验证的元数据则执行区块链上的代码。

如果你的源包含多个合约,输出会包括每个合约一个入口,对应的合约信息对象可以用作为属性名称的合约名字检索到。你可以通过检测当前的GlobalRegistrar代码来试一下:

contracts = eth.compile.solidity(globalRegistrarSrc)

5创建和部署合约

开始阅读这一节之前,确保你有解锁的账户和一些资金。

现在在区块链上创建一个合约,方法是用上一章节的以太坊虚拟机代码作为数据给空地址发送交易。示例如下:

注意:用在线Solidity实时编译器或Mix IDE程序会更容易完成。

var primaryAddress = eth.accounts[0]

var abi = [{ constant: false, inputs: [{ name: ‘a’, type: ‘uint256’ } ]

var MyContract = eth.contract(abi)

var contract = MyContract.new(arg1, arg2, …, {from: primaryAddress, data: evmByteCodeFromPrevio

所有的二进制数据都以十六进制的格式序列化。十六进制字符串总会有一个十六进制前缀0x。

注意:注意arg1, arg2, …是合约构造函数参数,以备它要接受参数。如果合约不需要构造函数参数,就可以忽略这些参数。

值得指出的是,这一步骤需要你支付执行。一旦交易成功进入到区块,你的账户余额(你作为发送方放在from领域)会根据以太坊虚拟机的gas规则被扣减。一段时间以后,你的交易会在一个区块中出现,确认它带来的状态是共识。你的合约现在存在于区块链上。

以不同步的方式做同样的事看起来是这样:

MyContract.new([arg1, arg2, …,]{from: primaryAccount, data: evmCode}, function(err, contract) {

if (!err && contract.address)

console.log(contract.address);

});

6与合约互动

与合约互动典型的做法是用诸如eth.contract()功能的抽象层,它会返回到javascript对象,和所有可用的合约功能一起,作为可调用的javascript功能。

描述合约可用功能的标准方式是ABI定义。这个对象是一个字符串,它描述了调用签名和每个可用合约功能的返回值。示例如下:

var Multiply7 = eth.contract(contract.info.abiDefinition);

var myMultiply7 = Multiply7.at(address);

现在ABI中具体说明的所有功能调用都在合约实例中可用。你可以用两种方法中的一种来调用这些合约实例上的方法。

myMultiply7.multiply.sendTransaction(3, {from: address})

“0x12345”

myMultiply7.multiply.call(3)

21

当用sendTransaction被调用的时候,功能调用通过发送交易来执行。需要花费以太币来发送,调用会永久记录在区块链上。用这种方式进行的调用返回值是交易散表。

当用call被调用的时候,功能在以太坊虚拟机被本地执行,功能返回值和功能一起返回。用这种方式进行的调用不会记录在区块链上,因此也不会改变合约内部状态。这种调用方式被称为恒定功能调用。以这种方式进行的调用不花费以太币。

如果你只对返回值感兴趣,那么你应该用call。如果你只关心合约状态的副作用,就应该用sendTransaction。

在上面的例子中,不会产生副作用,因此sendTransaction只会烧gas,增加宇宙的熵。

7合约元数据

在之前的章节中,揭示了怎样在区块链上创建合约。现在来处理剩下的编译器输出,合约元数据或者说合约信息。

在与不是你创建的合约互动时,你可能会想要文档或者查看源代码。合约作者被鼓励提供这样的可见信息,他们可以在区块链上登记或者借助第三方服务,比如说EtherChain。管理员API为所有选择登记的合约提供便利的方法来获取这个捆绑。示例如下:

// get the contract info for contract address to do manual verification

var info = admin.getContractInfo(address) // lookup, fetch, decode

var source = info.source;

var abiDef = info.abiDefinition

这项工作的潜在机制是:

合约信息被可以公开访问的URI上传到可辨认的地方。
任何人都可以只知道合约地址就找到是什么URI。
仅通过2个步骤的区块链注册就可以实现这些要求。第一步是在被称作HashReg的合约中用内容散表注册合约代码(散表)。第二步是在UrlHint合约用内容散表注册一个url。这些注册合约是Frontier版本的一部分,已经参与到Homestead中。

要知道合约地址来查询url,获取实际合约元数据信息包,使用这一机制就足够了。

如果你是个尽职的合约创建者,请遵循以下步骤:

将合约本身部署到区块链
获取合约信息json文件
将合约信息json文件部署到你选择的任意url
注册代码散表 ->内容散表 -> url
JS API通过提供助手把这个过程变得非常容易。 调用admin.register从合约中提取信息,在指定文件中写出json序列,运算文件的内容散表,最终将这个内容散表注册到合约代码散表。一旦将那个文件部署到任意url,你就能用admin.registerUrl来注册url 和你区块链上的内容散表(注意,一旦固定的内容选址模式被用作文件商店,url-hint不再必要了) 。

source = "contract test { function multiply(uint a) returns(uint d) { return a

7; } }"

// compile with solc

contract = eth.compile.solidity(source).test

// create contract object

var MyContract = eth.contract(contract.info.abiDefinition)

// extracts info from contract, save the json serialisation in the given file,

contenthash = admin.saveInfo(contract.info, “~/dapps/shared/contracts/test/info.json”)// send off the contract to the blockchain

MyContract.new({from: primaryAccount, data: contract.code}, function(error, contract){

if(!error && contract.address) {

// calculates the content hash and registers it with the code hash in HashReg

// it uses address to send the transaction.

// returns the content hash that we use to register a url

admin.register(primaryAccount, contract.address, contenthash)

// here you deploy ~/dapps/shared/contracts/test/info.json to a url

admin.registerUrl(primaryAccount, hash, url)

}

});

8测试合约和交易

在为交易和合约排除故障时,你通常会需要一些低级的测试策略。这一章节将介绍一些你可以用到的排错工作和做法。为了测试合约和交易而不产生实际的后果,最好在私有区块链上测试。这可以通过配置一个替代网络ID (选择一个特别的数字)和/或不能用的端点来实现。推荐做法是,为了测试你用一个替代数据目录和端口,这样就不会意外地和实时运行的节点冲突(假定用默认运行。在虚拟机排错模式开启geth,推荐性能分析和最高的日志冗余级别):

geth --datadir ~/dapps/testing/00/ --port 30310 --rpcport 8110 --networkid 4567890 --nodiscover -

提交交易之前,你需要创建私有测试链(参阅测试网络相关章节),示例如下:

// create account. will prompt for password

personal.newAccount();

// name your primary account, will often use it

primary = eth.accounts[0];

// check your balance (denominated in ether)

balance = web3.fromWei(eth.getBalance(primary), “ether”);

// assume an existing unlocked primary account

primary = eth.accounts[0];

// mine 10 blocks to generate ether

// starting miner

miner.start(4);

// sleep for 10 blocks (this can take quite some time).

admin.sleepBlocks(10);

// then stop mining (just not to burn heat in vain)

miner.stop();

balance = web3.fromWei(eth.getBalance(primary), “ether”);

创建交易之后,你可以用下面的命令来强制运行:

miner.start(1);

admin.sleepBlocks(1);

miner.stop();

你也可以用以下命令查看即将发生的交易:

// shows transaction pool

txpool.status

// number of pending txs

eth.getBlockTransactionCount(“pending”);

// print all pending txs

eth.getBlock(“pending”, true).transactions

如果你提交合约创建交易,可以检查想要的代码是否实际上嵌入到当前的区块链:

txhash = eth.sendTansaction({from:primary, data: code})

//… mining

contractaddress = eth.getTransactionReceipt(txhash);

eth.getCode(contractaddress)

相关文章:

人机猜拳(这是最近的一个总结)

人机猜拳是我自己原创的一段代码,我刚学完do-while,知识有限,但自己感觉写的这段代码是我的一个小巅峰,发出来让大家看看,新手能学到东西的话是极好的,然后更多的是想让一些老鸟给点建议。这个写代码很枯燥…

利用python3 调用zabbix接口完成批量加聚合图形(screens)

在上一篇博客中,我们完成的利用python3 调用zabbix接口批量增加主机,增加主机的item,增加主机的图形! 接下来我们完成批量增加主机的screen 首先我们要增加screen需要哪些参数呢?官方的解释如下: {"jsonrpc"…

轮播切换_javascript基础(一)——轮播图

javascript基础(一)——轮播图1、轮播图的实现原理轮播图的js实现原理其实十分的简单,首先将图片放入一个ul标签中,ul标签的大小要足够将所有图片放入其中。然后再将ul标签放进div中,这个div的大小正好可以显示一整张图片,将其他图…

以太坊挖矿源码:clique算法

链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载。 clique 以太坊的官方共识算法是ethash算法,这在前文已经有了详细的分析: 它是基于POW的共识机制的,矿工需要通…

JS中简单原型的使用

转载于:https://www.cnblogs.com/hwgok/p/6163335.html

vuex+vue-router拦截

干就完了 项目中经常遇到这样一个场景,用户信息或者进行增删改的一些模块,需要根据用户是否登录,进行路由拦截,直接上代码 在store文件夹下的store.js中存放一个默认登录状态 /** store.js* */ import Vue from vue import Vuex …

通关制单机器人_2020关务节|“数字供应链与智能通关”论坛——如何打造云上跨境贸易生态圈...

点击标题下「蓝色微信名」可快速关注 随着跨境贸易的飞速发展,其涉及的有商流、信息流、资金流与物流。其中,物流特别是跨境物流,又是其中较为重要的一个环节。如何解决跨境贸易的物流物流困难?让我们来听听,欧坚集团副…

区块链技术世界

链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载。 2017年发展最火热的技术,我觉得一个人工智能AI,另一个当之无愧的是一个叫区块链东西。最典型的例子是,人类顶…

Python学习心得第一周-03练习2

#5. 求1-23-45 ... 99的所有数的和 res0 count1 while count <100:if count%2 0:res-countelse:rescountcount1 print(res) #6. 用户登陆&#xff08;三次机会重试&#xff09; count0 while count<3:nameinput(name:)passwordinput(password:)if nameztc and passwords…

与MySQL传统复制相比,GTID有哪些独特的复制姿势?

与MySQL传统复制相比&#xff0c;GTID有哪些独特的复制姿势? http://mp.weixin.qq.com/s/IF1Pld-wGW0q2NiBjMXwfg 陈华军&#xff0c;苏宁云商IT总部资深技术经理&#xff0c;从事数据库服务相关的开发和维护工作&#xff0c;之前曾长期从事富士通关系数据库的开发&#xff0c…

方法的运用_企业如何运用论坛做营销,千享科技分享技巧方法

随着互联网的普及&#xff0c;对企业的发展带来了很大的影响&#xff0c;传统的营销已经满足不了企业的发展&#xff0c;需要运用互联网来营销&#xff0c;企业也意识到了互联网营销的重要性&#xff0c;而做互联网营销可以分成几种形式进行&#xff0c;像百度知识营销、论坛营…

区块链开发入门

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自区块链技术社区&#xff0c;未经允许拒绝转载。 区块链这么火&#xff0c;可是你很快就会发现&#xff0c;想要入门区块链开发&#xff0c;尤其是想要从零开始学习区块链编程&#xff0c;根本都找…

linux怎么创建牡蛎_文件amp;目录小技巧 | Linux后门系列

0x01 Linux 目录技巧我们都知道 Windows 下文件和文件夹命名是有很多规则和限制的&#xff0c;但是可以通过一些程序来绕过限制&#xff0c;今天我们来看看 Linux 有哪些有趣的规则 参考 https://www.pathname.com/fhs/pub/fhs-2.3.pdf当然了&#xff0c;我这种人怎么可能按照官…

php简单算法之冒泡排序

<?php $arr [2,4,1,5,3,11,6,999,88,666,66,44,22,33,776];function getNewArr($arr){$count count($arr);//该层循环控制 需要冒泡的轮数for($i1;$i<$count;$i){//该层循环用来控制每轮 冒出一个数 需要比较的次数for($k0;$k<$count-$i;$k){if($arr[$k]>$arr[…

iOS单个应用程序的最大可用内存是多少?

iOS单个应用程序的最大可用内存是多少&#xff1f; StackOverflow上有人做了一些简单的测试&#xff0c;有限设备下迄今为止测到的结果&#xff1a; iPad1: 127MB/256MB/49% (大致crash临界值 / 总内存 / 占比)iPad2: 275MB/512MB/53%iPad3: 645MB/1024MB/62%iPad4: 585MB/102…

sql 存储过程和函数

最近在学习数据库&#xff0c;上课过程中总是在许多知识点有或多或少的问题&#xff0c;对于这些问题的产生&#xff0c;大概是由于我听课习惯所造成的吧&#xff0c;好啦&#xff0c;废话不多说&#xff0c;开始今天到主题吧。 首先介绍SQL的存储过程&#xff0c;先来给它定义…

怎樣制作线段动画_PPT动画还能这么做?我擦!动画源文件免费送你

擦除动画&#xff0c;可以说是基础得不能再基础PPT动画之一了&#xff0c;我们几乎可以在任何带有PPT动画效果的演示中找到它的踪影。简单的直线擦除效果可能大部分都会&#xff0c;那么把直线换成曲线呢&#xff1f;小小的变动都会让你措手不及。所以&#xff0c;你确定自己真…

Linux最大打开文件描述符数

1. 系统最大打开文件描述符数&#xff1a;/proc/sys/fs/file-max a. 查看 $ cat /proc/sys/fs/file-max 186405 2. 设置 a. 临时性 # echo 1000000 > /proc/sys/fs/file-max 2. 永久性&#xff1a;在/etc/sysctl.conf中设置 fs.file-max 1000000 2. 进程最大…

XMT.com超200万被区块链终端交易

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自区块链技术社区&#xff0c;未经允许拒绝转载。 狭义来讲&#xff0c;区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构&#xff0c; 并以密码学方式保证的不可篡改和…

初学LINQ语句

//有两个数组&#xff0c;客户和地址&#xff0c;他们之间通过公司名关联&#xff1a;var customers new[] { new {CustomerID1,FirstName"Kim",LastName"Abercrombie",CompanyName"Alpine Sky House"},new {CustomerID2,FirstName"Jeff&q…

android 开启一个定时线程_ANDROID开发中定时器的3种方法

在android中&#xff0c;经常用到的定时器主要有以下几种实现&#xff1a;一、采用Handler与线程的sleep(long )方法二、采用Handler的postDelayed(Runnable, long) 方法三、采用Handler与timer及TimerTask结合的方法。下面逐一介绍&#xff1a;一、采用Handle与线程的sleep(lo…

083 HBase的完全分布式的搭建与部署,以及多master

一&#xff1a;前提准备 1.设置时间同步 2.清空logs&#xff0c;datas 3.格式化集群 bin/hdfs namenode -format 4.重启集群 sbin/start-dfs.sh sbin/start-yarn.sh 5.删除zookeeper下的data&#xff0c;并新建zkData 6.在zkData下新建myid 7.分发&#xff0c;后&#xff0c;修…

区块链技术指北

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自区块链技术社区&#xff0c;未经允许拒绝转载。 回顾近现代几次工业革命&#xff0c;人类的发展随着技术的变革而突飞猛进。第一次工业革命革命&#xff0c;以工作机的诞生为开始&#xff0c;以蒸…

cmd查看所有数据库 db2_DB2数据库常用命令集

【IT168 技术】在DB2的开发过程中&#xff0c;贯穿整个开发过程还有很重要的一部分工作就是数据库的维护&#xff1b;对于维护一个庞大信息系统来说是非常必要的&#xff1b;留一份简易的维护手册&#xff0c;以备不时之需&#xff1b;以下收集到的部分维护命令&#xff0c;以飨…

[原创]SparkR针对mysql的数据读写操作实现

网上翻了两天没找到一份有用的文章&#xff0c;自己研究SparkR的官方api文档&#xff0c;总算找到了实现的接口 我是用R语言加载SparkR库的方式&#xff0c;当然也可以直接用SparkR控制台就不用自己加载SparkR的库了 #首先加载sparkR的库 Sys.setenv(TEST_HOME "/root/so…

使用vue2.0 vue-router vuex 模拟ios7操作

其实你也可以&#xff0c;甚至做得更好... 首先看一下效果&#xff1a;用vue2.0实现SPA&#xff1a;模拟ios7操作 与 通讯录实现 github地址是&#xff1a;https://github.com/QRL909109/ios7 如果您觉得可以&#xff0c;麻烦给一个star&#xff0c;支持我一下。 之前接触过Ang…

区块链技术是否会终结开源时代?

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自区块链技术社区&#xff0c;未经允许拒绝转载。 2017年11月18~19日&#xff0c;在上海交大召开的2017中国开源年会&#xff0c;在第二天我们组织了一个“闭门会议”。在这个闭门会议上&#xff0c…

Direct2D开发:Direct2D 和 GDI 互操作性概述

本主题说明如何结合使用 Direct2D 和 GDI&#xff08;可能为英文网页&#xff09;。有两种方法可以结合使用 Direct2D 和 GDI&#xff1a;您可以将 GDI 内容写入与 Direct2D GDI 兼容的呈现器目标&#xff0c;也可以将 Direct2D 内容写入 GDI 设备上下文 (DC) 0X01 将Direct2D内…

vmware虚拟机启动centOs黑屏

如图所示 &#xff0c; 我的VM 启动虚拟机之后就变成了上面的样子&#xff0c;一直不动&#xff0c;ping也ping不好&#xff0c;这个时候 &#xff1a; 1. 要么 内存不够了&#xff1b; 2. 要么 网络协议存在问题了&#xff1b; 本地windows环境在管理员的cmd命令行输入 &…

plc和pc串口通讯接线_让你搞懂PLC串口通讯和通讯接口,这东西估计没几个能说清楚~...

电力作业人员在使用PLC的时候会接触到很多的通讯协议以及通讯接口&#xff0c;最基本的PLC串口通讯和基本的通讯接口你都了解吗&#xff1f;1&#xff0c;什么是串口通讯&#xff1f;串口是计算机上一种非常通用设备通信的协议(不要与通用串行总线Universal Serial Bus或者USB混…