什么是智能合约

一个智能合约是一套以数字形式定义的承诺(promises) ,包括合约参与方可以在上面执行这些承诺的协议。一个合约由一组代码(合约的函数)和数据(合约的状态)组成,并且运行在以太坊虚拟机上.

以太坊虚拟机(EVM)使用了256比特长度的机器码,是一种基于堆栈的虚拟机,用于执行以太坊智能合约 。由于EVM是针对以太坊体系设计的,因此使用了以太坊账户模型(Account Model)进行价值传输。

合约的代码具有什么能力:

读取交易数据。

读取或写入合约自己的存储空间。

读取环境变量(块高,哈希值,gas)

向另一个合约发送一个“内部交易”。

1. 什么是solidity

Solidity是一种智能合约高级语言,运行在Ethereum虚拟机(EVM)之上。

solidity 语言特点

它的语法接近于Javascript,是一种面向对象的语言。但作为一种真正意义上运行在网络上的去中心合约,它有很多的不同点:

异常机制,类似于事务的原子性。一旦出现异常,所有的执行都将会被回撤,这主要是为了保证合约执行的原子性,以避免中间状态出现的数据不一致。

运行环境是在去中心化的网络上,会比较强调合约或函数执行的调用的方式。因为原来一个简单的函数调用变为了一个网络上的节点中的代码执行

存储是使用网络上的区块链,数据的每一个状态都可以永久存储。

2. 开发的工具

Visual Studio Code + solidity 插件

WeBase 开发工具

3 快速入门

准备工作

搭建FISCO-BCOS块链,详细安装见文档

安装WeBASE-Front,详细见文档 , 修改相关配置,启动服务。

以下例子演示,依赖于上面的两个步骤。

3.1 开发合约

合约开发步骤:

1. 写合约

2. 编译合约

3. 部署合约

4. 测试合约

5. 生成java文件

说明:WeBase 帮助用户开发、测试和生成对应的Java类,用户获取java类,可以直接进行业务开发,加快开发进度和效率。

3.1.1. 获取合约例子

pragma solidity ^0.4.24;

contract HelloWorld {

string name;

function HelloWorld() {

name = "Hello, World!";

}

function get()constant returns(string) {

return name;

}

function set(string n) {

name = n;

}

}

3.1.2. 部署合约到区块链上

编译合约

编译合约

调用get方法

调用set方法

检查调用情况

3.1.4. 生成Java

3.1.5 应用开发

下载应用脚手架

$ git clone https://github.com/FISCO-BCOS/spring-boot-starter.git

导入文件进行配置开始开发

[更多工具和例子]()

3.2.1 引入概念:

address:以太坊地址的长度,大小20个字节,160位,所以可以用一个uint160编码。地址是所有合约的基础,所有的合约都会继承地址对象,也可以随时将一个地址串,得到对应的代码进行调用。合约的地址是基于账号随机数和交易数据的哈希计算出来的

ABI:是以太坊的一种合约间调用时或消息发送时的一个消息格式。就是定义操作函数签名,参数编码,返回结果编码等。

交易:以太坊中“交易”是指存储从外部账户发出的消息的签名数据包。

简单理解是:只要对区块链进行写操作,一定会发生交易。

交易回执:发生交易后的返回值

3.2.2 扩展阅读:

3.3 合约文件结构简介

版本声明

pragma solidity ^0.4.24;

状态变量(State Variables)

string name;

详细说明见下文

函数(Functions)

function get()constant returns(string) {

return name;

}

function set(string n) {

name = n;

}

事件(Events)

//事件的声明

event AddMsg(address indexed sender, bytes32 msg);

//事件的使用

function setData(int256 x) public {

storedData = x;

AddMsg(msg.sender, "in the set() method");

}

结构类型(Structs Types)

contract Contract {

struct Data {

uint deadline;

uint amount;

}

Data data;

function set(uint id, uint deadline, uint amount) {

data.deadline = deadline;

data.amount = amount;

}

}

函数修饰符(Function Modifiers)

类似于hook

modifier only_with_at_least(int x) {

if (x >= 5) {

x = x+10;

_;

}

}

4. 合约编程模式COP

面向条件的编程(COP)是面向合约编程的一个子域,作为一种面向函数和命令式编程的混合模式。COP解决了这个问题,通过需要程序员显示地枚举所有的条件。逻辑变得扁平,没有条件的状态变化。条件片段可以被正确的文档化,复用,可以根据需求和实现来推断。重要的是,COP在编程中把预先条件当作为一等公民。这样的模式规范能保证合约的安全。

4.1 FEATURES

函数主体没有条件判断

例子:

contract Token {

// The balance of everyone

mapping (address => uint) public balances;

// Constructor - we're a millionaire!

function Token() {

balances[msg.sender] = 1000000;

}

// Transfer `_amount` tokens of ours to `_dest`.

function transfer(uint _amount, address _dest) {

balances[msg.sender] -= _amount;

balances[_dest] += _amount;

}

}

改进后:

function transfer(uint _amount, address _dest) {

if (balances[msg.sender] < _amount)

return;

balances[msg.sender] -= _amount;

balances[_dest] += _amount;

}

COP的风格

modifier only_with_at_least(uint x) {

if (balances[msg.sender] >= x) _;

}

function transfer(uint _amount, address _dest)

only_with_at_least(_amount) {

balances[msg.sender] -= _amount;

balances[_dest] += _amount;

}

扩展阅读:

5. 语法介绍

5.1 值类型

布尔(Booleans)true false支持的运算符

!逻辑非&& 逻辑与|| 逻辑或== 等于!= 不等于

整型(Integer)int/uint:变长的有符号或无符号整型。变量支持的步长以8递增,支持从uint8到uint256,以及int8到int256。需要注意的是,uint和int默认代表的是uint256和int256

地址(Address):以太坊地址的长度,大小20个字节,160位,所以可以用一个uint160编码。地址是所有合约的基础,所有的合约都会继承地址对象,也可以随时将一个地址串,得到对应的代码进行调用

定长字节数组(fixed byte arrays)

有理数和整型(Rational and Integer Literals,String literals)

枚举类型(Enums)

函数(Function Types)

5.2 引用类型(Reference Types)

不定长字节数组(bytes)

字符串(string)

数组(Array)

结构体(Struts)

6. 重要概念

6.1 Solidity的数据位置

数据位置的类型

变量的存储位置属性。有三种类型,memory,storage和calldata。

memory存储位置同我们普通程序的内存类似。即分配,即使用,越过作用域即不可被访问,等待被回收-

storage的变量,数据将永远存在于区块链上。

calldata 数据位置比较特殊,一般只有外部函数的参数(不包括返回参数)被强制指定为calldata

Storage - 状态变量的存储模型

大小固定的变量(除了映射,变长数组以外的所有类型)在存储(storage)中是依次连续从位置0开始排列的。如果多个变量占用的大小少于32字节,会尽可能的打包到单个storage槽位里,具体规则如下:

在storage槽中第一项是按低位对齐存储(lower-order aligned)

基本类型存储时仅占用其实际需要的字节。

如果基本类型不能放入某个槽位余下的空间,它将被放入下一个槽位。

结构体和数组总是使用一个全新的槽位,并占用整个槽(但在结构体内或数组内的每个项仍遵从上述规则)

优化建议:

为了方便EVM进行优化,尝试有意识排序storage的变量和结构体的成员,从而让他们能打包得更紧密。比如,按这样的顺序定义,uint128, uint128, uint256,而不是uint128, uint256, uint128。因为后一种会占用三个槽位。

Memory - 内存变量的布局(Layout in Memory)

Solidity预留了3个32字节大小的槽位:

0-64:哈希方法的暂存空间(scratch space)

64-96:当前已分配内存大小(也称空闲内存指针(free memory pointer))

暂存空间可在语句之间使用(如在内联编译时使用)

Solidity总是在空闲内存指针所在位置创建一个新对象,且对应的内存永远不会被释放(也许未来会改变这种做法)。

有一些在Solidity中的操作需要超过64字节的临时空间,这样就会超过预留的暂存空间。他们就将会分配到空闲内存指针所在的地方,但由于他们自身的特点,生命周期相对较短,且指针本身不能更新,内存也许会,也许不会被清零(zerod out)。因此,大家不应该认为空闲的内存一定已经是清零(zeroed out)的。

例子

6.2 address

以太坊地址的长度,大小20个字节,160位,所以可以用一个uint160编码。地址是所有合约的基础,所有的合约都会继承地址对象,也可以随时将一个地址串,得到对应的代码进行调用

6.3 event

event AddMsg(address indexed sender, bytes32 msg);

这行代码声明了一个“事件”。客户端(服务端应用也适用)可以以很低的开销来监听这些由区块链触发的事件

事件是使用EVM日志内置功能的方便工具,在DAPP的接口中,它可以反过来调用Javascript的监听事件的回调。

var event = instance.AddMsg({}, function(error, result) {

if (!error) {

var msg = "AddMsg: " + utils.hex2a(result.args.msg) + " from "

console.log(msg);

return;

} else {

console.log('it error')

}

});

事件在合约中可被继承。当被调用时,会触发参数存储到交易的日志中(一种区块链上的特殊数据结构)。这些日志与合约的地址关联,并合并到区块链中,只要区块可以访问就一直存在(至少Frontier,Homestead是这样,但Serenity也许也是这样)。日志和事件在合约内不可直接被访问,即使是创建日志的合约。

日志位置在nodedir0/log 里面,可以打出特殊的类型进行验证

6.4 数组

数组是定长或者是变长数组。有length属性,表示当前的数组长度。

bytes:类似于byte[], 动态长度的字节数组

string:类似于bytes,动态长度的UTF-8编码的字符类型

bytes1~bytes32

一般使用定长的 bytes1~bytes32。在知道字符串长度的情况下,指定长度时,更加节省空间。

6.4.1 创建数组

字面量 uint[] memory a = []

new uint[] memory a = new uint[](7);

例子

pragma solidity ^0.4.0;

contract SimpleStartDemo{

uint[] stateVar;

function f(){

//定义一个变长数组

uint[] memory memVar;

//不能在使用new初始化以前使用

//VM Exception: invalid opcode

//memVar [0] = 100;

//通过new初始化一个memory的变长数组

memVar = new uint[](2);

//不能在使用new初始化以前使用

//VM Exception: invalid opcode

//stateVar[0] = 1;

//通过new初始化一个storage的变长数组

stateVar = new uint[](2);

stateVar[0] = 1;

}

}

6.4.2 数组的属性和方法

length属性

storage变长数组是可以修改length

memory变长数组是不可以修改length

push方法

storage变长数组可以使用push方法

bytes可以使用push方法

pragma solidity ^0.4.2;

contract SimpleStartDemo {

uint[] stateVar;

function f() returns (uint){

//在元素初始化前使用

stateVar.push(1);

stateVar = new uint[](1);

stateVar[0] = 0;

//自动扩充长度

uint pusharr = stateVar.push(1);

uint len = stateVar.length;

//不支持memory

//Member "push" is not available in uint256[] memory outside of storage.

//uint[] memory memVar = new uint[](1);

//memVar.push(1);

return len;

}

}

下标:和其他语言类似

6.4.3 Memory数组

如果Memory数组作为函数的参数传递,只能支持ABI能支持的类型类型。

Memory数组是不能修改修改数组大小的属性

例子

pragma solidity ^0.4.2;

contract SimpleStartDemo {

function f() {

//创建一个memory的数组

uint[] memory a = new uint[](7);

//不能修改长度

//Error: Expression has to be an lvalue.

//a.length = 100;

}

//storage

uint[] b;

function g(){

b = new uint[](7);

//可以修改storage的数组

b.length = 10;

b[9] = 100;

}

}

EVM的限制

由于EVM的限制,不能通过外部函数直接返回动态数组和多维数组

将stroage数组不能直接返回,需要转换成memory类型的返回

//Data层数据

struct Rate {

int key1;

int unit;

uint[3] exDataArr;

bytes32[3] exDataStr;

}

mapping(int =>Rate) Rates;

function getRate(int key1) public constant returns(int,uint[3],bytes32[3]) {

uint[3] memory exDataInt = Rates[key1].exDataArr;

bytes32[3] memory exDataStr = Rates[key1].exDataStr;

return (Rates[key1].unit,exDataInt,exDataStr);

}

业务场景

6.5 函数

function () {internal(默认)|external} constant [returns ()]

6.5.1 函数的internal与external

pragma solidity ^0.4.5;

contract FuntionTest{

function internalFunc() internal{}

function externalFunc() external{}

function callFunc(){

//直接使用内部的方式调用

internalFunc();

//不能在内部调用一个外部函数,会报编译错误。

//Error: Undeclared identifier.

//externalFunc();

//不能通过`external`的方式调用一个`internal`

//Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest

//this.internalFunc();

//使用`this`以`external`的方式调用一个外部函数

this.externalFunc();

}

}

contract FunctionTest1{

function externalCall(FuntionTest ft){

//调用另一个合约的外部函数

ft.externalFunc();

//不能调用另一个合约的内部函数

//Error: Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest

//ft.internalFunc();

}

}

访问函数有外部(external)可见性。如果通过内部(internal)的方式访问,比如直接访问,你可以直接把它当一个变量进行使用,但如果使用外部(external)的方式来访问,如通过this.,那么它必须通过函数的方式来调用。

pragma solidity ^0.4.2;

contract SimpleStartDemo {

uint public c = 10;

function accessInternal() returns (uint){

return c;

}

function accessExternal() returns (uint){

return this.c();

}

}

6.5.2 函数调用

内部调用,不会创建一个EVM调用,也叫消息调用

外部调用,创建EVM调用,会发起消息调用

6.5.3 函数修改器(Function Modifiers)

修改器(Modifiers)可以用来轻易的改变一个函数的行为。比如用于在函数执行前检查某种前置条件。修改器是一种合约属性,可被继承,同时还可被派生的合约重写(override)

pragma solidity ^0.4.2;

contract SimpleStartDemo {

int256 storedData;

event AddMsg(address indexed sender, bytes32 msg);

modifier only_with_at_least(int x) {

if (x >= 5) {

x = x+10;

_;

}

}

function setData(int256 x) public only_with_at_least(x){

storedData = x;

AddMsg(msg.sender, "[in the set() method]");

}

}

6.5.4合约构造函数 同名函数

可选

仅能有一个构造器

不支持重载

6.6 Constant

函数也可被声明为常量,这类函数将承诺自己不修改区块链上任何状态。

一般从链上获取数据时,get函数都会加上constant

6.7 继承(Inheritance)

Solidity通过复制包括多态的代码来支持多重继承。

父类

pragma solidity ^0.4.4;

contract Meta {

string public name;

string public abi;

address metaAddress;

function Meta(string n,string a){

name=n;

abi=a;

}

function getMeta()public constant returns(string,string,address){

return (name,abi,metaAddress);

}

function setMetaAddress(address meta) public {

metaAddress=meta;

}

}

子类

pragma solidity ^0.4.4;

import "Meta.sol";

contract Demo is Meta{

bytes32 public orgID;

function Demo (string n,string abi,bytes32 id) Meta(n,abi)

{

orgID = id;

}

}

7. 限制

基于EVM的限制,不能通过外部函数返回动态的内容

please keep in mind

Fail as early and loudly as possible

Favor pull over push payments

Order your function code: conditions, actions, interactions

Be aware of platform limits

Write tests

Fault tolerance and Automatic bug bounties

Limit the amount of funds deposited

Write simple and modular code

Don’t write all your code from scratch

Timestamp dependency: Do not use timestamps in critical parts of the code, because miners can manipulate them

Call stack depth limit: Don’t use recursion, and be aware that any call can fail if stack depth limit is reached

Reentrancy: Do not perform external calls in contracts. If you do, ensure that they are the very last thing you do

8. 语言本身存在的痛点

ABI支持的类型有限,难以返回复杂的结构体类型。

Deep Stack的问题

难以调试,只能靠event log ,进行合约的调试

合约调用合约只能使用定长数组

9. 合约架构

9.1. 合约架构分层

实用架构示意图

合约的架构分两层数据合约和逻辑合约,方便后期合约的升级。更多详情,请参见浅谈以太坊智能合约的设计模式与升级方法 。

9.2. 更多合约更新架构和方法

10. 参考资料

欢迎大家贡献和分享,一起来学习区块链~

区块链技术c java_区块链技术:智能合约入门相关推荐

  1. 分享实录|区块链技术与智能合约入门(开发实例)

    2019独角兽企业重金招聘Python工程师标准>>> 1 什么是区块链 1.1白话讲解区块链 现在区块链特别火,可能大家都听说过区块链,听说过比特币,那到底什么是区块链? 前几天和 ...

  2. 区块链技术最佳的监管方式是智能合约监管智能合约

    区块链最新消息 1.在国内首部<区块链安全生存指南>发布 最新消息:比特大.长亭科技和ConsenSys陆联手发布了全国首部<区块链安全生存指南>.该指南围绕区块链技术安全,对 ...

  3. 区块链智能合约入门:Hello world(2)

    这次的基础合约Hello world 有所升级,增加了updateMessage,让你可以随时更新自己想说的话. 其实在区块链智能合约入门:Hello world(1)这篇文章里已经介绍过,Hello ...

  4. 区块链之智能合约入门

    区块链之智能合约入门 第一步 安装环境 首先这里写的合约是指solidity合约,使用Remix IDE.所以我们第一步就是安装Remix IDE.remix ide是开发以太坊智能合约的神器,支持网 ...

  5. 区块链技术:智能合约入门

    什么是智能合约 一个智能合约是一套以数字形式定义的承诺(promises) ,包括合约参与方可以在上面执行这些承诺的协议.一个合约由一组代码(合约的函数)和数据(合约的状态)组成,并且运行在以太坊虚拟 ...

  6. 区块链:1、基础技术 哈希、数字签名、智能合约

    区块链:1.基础技术 一.哈希运算(Hash Algorithm) 1.概念 哈希运算即散列算法.其功能就是可以将任意长度输入通过一定计算生成一个固定长度的字符串,输出的这个字符串即输入的哈希值. 2 ...

  7. 区块链——智能合约入门知识

    文章目录 1.区块链安全体系架构 分法1 分法2(类似分法1) 分法3 2.变量 2-1.变量 变量的声明: 变量的分类: 2-2.类型 值类型: 引用类型: 3.语句 4.函数 5.ERC20标准 ...

  8. 10本区块链热门图书(应用开发、智能合约等)免费送!

    欢迎访问网易云社区,了解更多网易技术产品运营经验. "互联网之后就是区块链时代,区块链是实现未来跟踪经济的关键技术."世界上真的存在 100% 去中心化的系统吗?区块链到底是什么? ...

  9. GRE:区块链将引领传统保险走向风险智能合约的时代变革

    点击上方 "蓝色字" 可关注我们! 编辑:铅笔盒 北京时间3月28日,每月两次的行业盛会[ ICT创新创业"深度脑洞聚会"]在上海举行,目前已举办235期.历时 ...

最新文章

  1. evo-评估SLAM轨迹
  2. file invalid or corrupt. -vs2010
  3. C++随笔——虚拟继承
  4. tf.variable_scope和tf.name_scope的用法
  5. CSS基础:text-overflow:ellipsis溢出文本的显示样式
  6. css3 filter url,CSS3 filter(滤镜) 属性
  7. c4503文件服务器,理光C3503/C4503/C5503检查状态下各项目说明解释
  8. python并发处理机制_Python并发编程—同步互斥
  9. 22考研英语高频词汇
  10. Class文件格式总结
  11. 【论文导读】Continuity Scaling: A Rigorous Framework for Detecting andQuantifying Causality Accurately
  12. vba formula 公式的引用
  13. win怎么更换计算机密码错误,win10系统更改开机密码提示“Windows不能更改密码”的解决方法...
  14. 阿里云账号注册流程方法(图文教程)
  15. 【NOTE】python3.6下scons运行提示找不到SCons.Script解决方式
  16. 2020年光通信市场下光缆生产发展的宏观分析
  17. gps转百度地图坐标 java,GPS坐标与百度地图坐标转换
  18. MySQL 安装报错的解决方法
  19. Qt实现播放Flash
  20. 计算机专业跨考会计好处,细数跨考会计的各种好处

热门文章

  1. 领导跟跟你说让你多和他沟通,但是你不知道该沟通什么?怎么破?
  2. 交换排序 java_java排序算法-交换排序
  3. 做好生产排程,这六大要素非常重要
  4. 项目中添加音效--依旧的简单使用
  5. 【shell】shell脚本实战-shell数组
  6. linux安全狗 停止服务,安全狗linux,windows安装设置
  7. Udacity数据分析(进阶)- 统计学:检验心理学现象
  8. LearnLua - 学习笔记
  9. Ubuntu20.04使用过程中总是弹出检测到系统程序出现问题的解决方法
  10. PCLl从Vlp-16录制好的bag包提取点云数据