ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Solidity

2021-03-16 10:32:31  阅读:147  来源: 互联网

标签:调用 函数 Solidity uint 数组 类型 合约


solidity语法接近于JavaScript,是一种面向对象的语言。但作为一种真正意义上运行在网络上的去中心化合约,它又有许多不同:
以太坊底层基于账户,而不是UTXO。所以增加了一个特殊的address的数据类型用于定位用户和合约账户。
语言内嵌框架支持支付。提供了payable等关键字,可以在语言层面直接支持支付。
使用区块链进行数据存储。数据的每一个状态都可以永久存储,所以在使用时需要确定变量使用内存,还是区块链存储。
运行环境是在去中心化的网络上,所以需要强调合约或函数执行的调用的方式。
不同的异常机制。一旦出现异常,所有的执行都将会被回撤,这主要是为了保证合约执行的原子性,以避免中间状态出现的数据不一致。

solidity源码和智能合约

Solidity源代码要成为可以运行在以太坊上的智能合约需要经历以下步骤:
1.用Solidity编写的智能合约源代码需要先使用编译器编译为字节码,编译过程中会同时产生智能合约的二进制接口规范
2.通过交易的方式将字节码部署到以太坊网络,每次成功部署都会产生一个新的智能合约账户
3.使用javaScript编写的DApp通常通过web3.js+ABI去调用智能合约中的函数来实现数据的读取和修改。

Solidity编译器
1.Remix
2.solcjs : npm install -g solc

源文件:
pragma (版本杂注)
pragma solidity ^0.4.0 源文件将既不允许低于0.4.0版本的编译器编译,也不允许高于0.5.0版本的编译器编译。

import(导入其它源文件)

Solidity支持的导入语句import,语法同javaScript非常相似
import “filename”; //从filename中导入所有的全局符号到当前的全局作用域中。
import * as symbolName from “filename”; //创建一个新的全局符号symbolName,其成员均来自“filename”中全局符号
import {symbol1 as alias,symbol2} from “filename”; //创建新的全局符号alias和symbol2,分别从“filename”引用symbol1和symbol2
import “filename” as symbolName; //等同于import * as symbolName from “filename”;

solidity值的类型

bool: true or false;
int/uint:分别表示有符号和无符号的不同位数的整型变量;支持关键字uint8到uint256以及int8到int256,以8位为步长递增
定长浮点型(fixed/ufixed):表示各种大小的有符号和无符号的定长浮点型;在关键字ufixedMxN和fixedMxN中,M表示该类型占用的位数,N表示可用的小数位数。
地址(address):存储一个20字节的值
定长字节数组:关键字有bytes1,bytes2,bytes3,…bytes32
枚举(enum):一种用户可以定义类型的方法,与C语言类似,默认从0开始递增,一般用来模拟合约的状态。
函数(function):一种表示函数的类型

solidity引用类型

数组(Array)
定长数组/动态数组
storage存储型数组元素类型可以是任意的,memory内存类型数组元素类型不能是映射(mapping)类型。
结构(struct)
Solidity支持通过构造结构体的形式定义新的类型
映射(Mapping)
映射可以视为哈希表,在实际的初始化过程中创建每个可能的key,并将其映射到字节形式全是0的值。

solidity地址类型

address
地址类型存储一个20字节的值;地址类型也有成员变量,并作为所有合约的基础
address payable
多出了transfer和send两个成员变量
两者区别和转换:
payable地址可以发送ether地址,而普通不行。
允许从payable address 到address的隐式转换,而反过来不行。
从0.5.0版本起,合约不再是从地址类型派生而来,但如果它有payable的回退函数,那同样可以显式转换为address或者address payable类型。

地址类型成员变量

.balance(uint256):该地址的以太余额,以wei为单位
.transfer(uint256 amount):向指定地址发送数量为amount的ether,失败时抛出异常,发送2300gas的矿工费,不可调节。
.send(uint256 amount) returns(bool):向指定地址发送数量为amount的ether,失败时返回false,发送2300gas的矿工费,不可调节。
.call(bytes memory) returns (bool,bytes memory):发出底层函数CALL,失败时返回false,发送所有可用gas,可调节。
.delegatecall(bytes memory) returns (bool,bytes memory):发出底层函数DELEGATECALL,失败时返回false,发送所有可用gas,可调节。

字符数组

定长字符数组,属于值类型,bytes1,bytes2,…bytes32代表长度1到32的字节序列。
有一个.length属性,返回数组长度
变长字符数组
属于引用类型,包括bytes和string,不同的是bytes是Hex字符串,而string是UTF-8编码的字符串。

数组

固定大小k和元素类型T的数组被写为T[k],动态大小的数组为T[]。例如,一个由5个uint动态数组组成的数组是uint[] [5]
要访问第三个动态数组中的第二个uint,可以使用x[2][1]
越界访问数组,会导致调用失败回退
如果要添加新元素,则必须使用.push()或将.length增大
变长的storage数组和bytes有一个push()方法。可以将一个新元素附加到数组末端,返回值为当前长度。

结构

结构类型可以在映射和数组中使用,它们本身可以包含映射和数组。
结构不能包含自己类型的成员,但可以作为自己数组成员的类型,也可以作为自己映射成员的值类型。

映射

声明一个映射:mapping
_KeyType可以是任何基本类型,这意味着它可以是任何内置值类型加上字符数组和字符串。不允许使用用户定义的或复杂的类型,如枚举,映射,结构以及除bytes和string之外的任何数组类型。

solidity数据位置

所有复杂类型,即数组、结构和映射类型,都有一个额外属性,“数据位置”,用来说明数据是保存在内存memory中还是存储在storage中。
大多数时候有默认位置,也可以在类型名后添加关键字storage或者memory进行修改。
函数参数的数据位置默认是memory,局部变量的数据默认位置是storage,状态变量的数据位置强制是storage。
另外还有第3种数据位置,calldata,只读且不会永久存储的位置,用来存储函数参数。外部函数的参数的数据位置被强制指定为calldata,效果跟memory差不多。

强制指定的数据位置:
外部函数的参数:calldata;状态变量:storage
默认数据位置:
函数参数:memory
引用类型的局部变量:storage
值类型局部变量:栈(stack)
特别要求:
公开可见的函数参数一定是memory类型,如果要求是storage类型,则必须是private或者internal函数,这是为了防止随意的公开调用占有资源。

示例错误程序:

运行f,b的值会随之改变。

contract F{
    uint public b;
    uint public a;
    uint[] public data;
    function f()public{
        uint[] x;
        x.push(2);
        data = x;
    }
}

x是没有初始化的storage指针,会指向合约最开始,即b的位置,x中会存储其长度,所以每运行一次f,b会增加1。

同样的错误例子:

蜜罐合约:

contract H{
    uint luckyNumber = 52;
    uint public last;
    struct Guess{
        address player;
        uint number;
    }
    Guess[] public guessHistory;
    function guess(uint _num) public{
        Guess newGuess;
        newGuess.player = msg.sender;
        newGuess.number = _num;
        guessHistory.push(newGuess);
        if(_num == luckyNumber){
            msg.sender.transfer(msg.value*2);
        }
    }
}

Solidity函数声明和类型

函数的值类型有两类:内部(internal)函数和外部(external)函数
内部函数只能在当前合约内被调用,因为它们不能在当前合约上下文的外部被执行。调用一个内部函数是通过跳转到它的入口标签来实现的,就像在当前合约的内部调用一个函数。
外部函数由一个地址和一个函数签名组成,可以通过外部函数调用传递或者返回。
调用内部函数:直接使用名字f
调用外部函数:this.f(当前合约),a.f(外部合约)

Solidity函数可见性

函数的可见性可以指定external,public,internal或者private:对于状态变量,不能设置为external,默认是internal。
external:外部函数作为合约接口的一部分,意味着我们可以从其他合约和交易中调用。一个外部函数f不能从内部调用。当收到大量数据的时候,外部函数有时候会更有效率。
public:public函数是合约接口的一部分,可以在内部或通过消息调用。对于public状态变量,会自动生成一个getter函数。
internal:这些函数和状态变量只能是内部访问,不使用this调用。即不能用.func的方式调用,直接调用即可。
private:private函数和状态变量仅在当前定义它们的合约中使用,并且不能被派生合约使用。

函数状态可变性

pure:纯函数,不允许修改或者访问
view:不允许修改状态
payable:允许从消息调用中接受以太币
constant:与view相同,一般只修饰状态变量,不允许赋值。
修改状态:
修改状态变量,产生事件,创建其他合约,使用selfdestruct,通过调用发送以太币,调用任何没有标记为view或者pure的函数,使用低级调用,使用包含特定操作码的内联汇编。
读取状态:
读取状态变量,访问this.balance或者

.balance,访问block,tx,msg中任意成员,调用任何未标记为pure的函数,使用包含某些操作码的内联汇编。

函数修饰器

使用修饰器modifier可以轻松改变函数的行为。例如:它们可以在函数执行前自动检查某个条件。修饰器modifier是合约的可继承属性,并可能被派生合约覆盖。
如果一个函数有多个修饰器modifier,可以以空格隔开,修饰器modifier会依次检查执行。
_表示函数体的位置。

回退函数(fallback)

回退函数(fallback) 是合约中的特殊函数;没有名字,不能有参数也不能有返回值。
如果在一个合约的调用中,没有其它函数与给定的函数标识符匹配,那么这个函数会被执行
每当合约收到以太币,回退函数就会执行。此外,为了接收以太币,fallback函数必须标记为payable。如果不存在这样的函数,则合约不能通过常规交易接收以太币。
上下文中通常只有很少的gas可以用来完成回退函数的调用,所以使fallback函数调用尽量廉价。

事件(event)

事件是EVM提供的一种日志基础设施。事件可以用来做操作记录,存储为日志。也可以用来实现一些交互功能,比如通知UI,返回函数调用结果等。
当定义的事件触发时,我们可以将事件存储到EVM的交易日志中,日志是区块链的一种特殊数据结构;日志与合约关联,与合约的存储合并存入区块链中;只要某个区块可以访问,其相关的日志就可以访问,但在合约中,我们不能直接访问日志和事件数据。
可以通过日志实现简单支付验证SPV,如果一个外部实体提供了一个带有这种证明的合约,它可以检查日志是否真实存在于区块链中。

Solidity异常处理

Solidity使用“状态恢复异常”来处理异常。这样的异常将撤销对当前调用中状态的所有更改,并且向调用者返回错误。
函数assert和require可用于判断条件,并在不满足条件时抛出异常
assert()一般只应用于测试内部错误,并检查常量
require()应用于确保满足有效条件,或验证调用外部合约的返回值。
revert()用于抛出异常,它可以标记一个错误并将当前调用回退。

单位

1 ether = 10^18 wei
1 finney = 10^15 wei
1 szabo = 10^12 wei
时间:
hours,seconds,weeks,days,years,minutes

标签:调用,函数,Solidity,uint,数组,类型,合约
来源: https://blog.csdn.net/SJTU_liangge/article/details/114677908

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有