Solidity是智能合约最常用的语言,语法上与JavaScript很接近,是一种面向对象的语言。用于生成在EVM(Ethereum Virtual Machine)上执行的机器级代码的工具。

数据类型

  • uint :用来定义一个无符号整型数字。

  • address:是Solidity语言的一个特有的数据类型,用来定义一个地址,长度为20字节。
            可以使用属性balance查询地址的当前以太币余额,并使用transfer函数将以太币发送到目标地址。

    下面是address类型的属性及成员函数:

    1
    2
    3
    4
    5
    6
    <address>.balance (uint256):address账户的余额(单位wei),uint类型,256位
    <address>.transfer(uint256 amount):当前合约向address转账
    <address>.send(uint256 amount) returns (bool):向address发送数量为amount的wei,失败时返回false
    <address>.call(...) returns (bool):当前合约发起调用,调用address合约里的函数
    <address>.callcode(...) returns (bool):发出底层CALLCODE
    <address>.delegatecall(...) returns (bool):代理调用

    注:transfer()函数和sent()函数的区别

            执行transfer()发生错误时,会产生连锁式的回滚,调用时消耗2300wei;

            执行sent()发生错误时,会返回一个false,而不会产生连锁式的回滚,调用时消耗2300wei。

            另外,使用\<address>.call().value(uint256 amount)也可以实现转账,不会产生连锁式的回滚,将剩余所有gas发送给目标address合约。

    下面是一个示例:

    1
    2
    3
    4
    5
    6
    7
    //定义目标地址
    address aim = 0x123456789abcdef;
    //获取本节点地址
    address myAddress = this;
    //向目标账户转账10 wei
    if(myAddress.balance > = 10)
    aim.transfer(10);
  • mapping:和其他语言中的哈希表(map)很像,用来定义一种映射。不同的是,mapping不提供对其中所有元素进行遍历的功能,要想实现该功能,只能用户自己想办法记录mapping中有哪些元素。

  • bool:布尔类型,可能的取值为常量值true和false。

  • bytes[1-32]:定长字节数组(长度取值范围为1-32),例如用bytes4可以定义一个长度为4个字节的字节数组,用bytes32可以定义一个长度为32个字节的字节数组。

  • enum:枚举类型是在Solidity中的一种用户自定义类型,和其他语言中的枚举类型类似。

  • string:字符串类型。

  • hex:十六进制字面量,以关键字hex打头,后面紧跟用单或双引号包裹的字符串。如hex”001122ff”。在内部会被表示为二进制流。

常用关键字

  • contract:定义一个智能合约。

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

  • constructor:用来定义构造函数;
  • function:用来定义成员函数,如果函数没有返回结果,则必须省略returns关键字。

        函数类型有两类;可分为内部函数(internal)和外部函数(external)函数。
        内部函数:因为不能在当前合约的上下文环境以外的地方执行,内部函数只能在当前合约内被使用。如在当前的代码块内,包括内部库函数,和继承的函数中。
        外部函数:外部函数由地址和函数方法签名两部分组成。可作为外部函数调用的参数,或者由外部函数调用返回。

  • emit:用来调用一个事件。
  • payable:以太坊中规定,如果一个账户能接受外部转账的话,那么相应的接受转账的函数需要标注成payable。
  • struct:用来定义自定义类型(最多只能有16个成员)。用法如下所示:
1
2
3
4
5
struct Auction{
address receiver;
address highest_bid;
uint amount;
}

货币单位

        一个字面量的数字,可以使用后缀wei,finney,szabo或ether来在不同面额中转换。不含任何后缀的默认单位是wei(以太坊中最小的货币单位)。

1
2
3
4
5
6
7
8
9
10
11
1 ether = 1,000,000,000,000,000,000 wei;

1 finney = 1,000,000,000,000,000 wei;

1 szabo = 1,000,000,000,000 wei;

1 shannon = 1,000,000,000 wei;

1 lovelace = 1,000,000 wei;

1 babbage = 1,000 wei;

外部账户调用智能合约

        创建一个交易,接收地址为要调用的那个智能合约的地址,data域填写要调用的函数及其参数的编码值,value域填写要转账的金额,gas used域是消耗的汽油费,gas limit是用户最多愿意支付多少汽油费,gas price是汽油价格。

一个合约调用另一个合约中的函数

1、直接调用
        例如B合约调用A合约,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//fun()函数用来实现向一个日志文件中写入一个字符串,返回一个uint类型的123
contract A{
event LogCallFun(string str);
function fun(strinng str) returns (uint){
emit LogCallFoo(str);
reutrn 123;
}
}
//callAFunDirectly()方法用来调用A中的fun()函数
contract B{
uint i;
//该函数的参数是一个合约的地址
function callAFunDirectly(address addr) public {
//将合约地址转换成合约A的实例
A a = A(addr);
i = a.fun("直接调用");
}
}

注:
(1)需要指出的是,合约不能自发调用另一个合约,而是有一个外部账户调用合约,然后该合约再调用另一个合约。
(2)如果在执行a.fun()过程中抛出错误,则callAFunDirectly也抛出错误,本次调用全部回滚。

2、使用address类型的call()函数
        call()函数的第一个参数被编码成4 个字节,表示要调用的函数的签名;其它参数会被扩展到 32 字节,表示要调用函数的参数。

1
2
3
4
5
6
7
8
contract C {
function callAFunByCall(address addr) public returns (bool){
bytes4 functionSig = bytes4(keccak256("fun(string)"));
if(addr.call(functionSig, "通过call调用))
return true;
return false;
}
}

注:与直接调用不同,如果在执行a.fun()过程中抛出错误,则call()函数返回一个false,不用回滚全部操作。

3、代理调用delegatecall()

  • 使用方法与call()相同
  • 与call()函数的区别在于是否切换上下文

        • call()切换到被调用的智能合约上下文中
        • delegatecall()只使用给定地址的代码,其它属性(存储,余额等)都取自当前合约。delegatecall 的目的是使用存储在另外一个合约中的库代码。

杂七杂八

  • Version Pragma

        Version Pragma是定义代码使用的Solidity编译器版本的声明。 该声明写在代码的第一行。如下所示:

1
version pragma ^0.4.00;
  • 导入其他源文件

        在全局级别,可以使用以下形式的import语句:

1
import "filename";
  • 继承

        Solidity中支持合约的继承,用is关键字,并且支持多继承。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
contract Owned {
address owner;
function owned() {
owner = msg.sender;
}
}
//继承
contract Mortal is Owned {
function kill(){
self-destruct(owner);
}
}
//多继承
contract User is Owned, Mortal
{
string public UserName;
function User(string _name){
UserName = _name;
}
}
  • fallback()函数

该函数的形式如下所示

1
2
3
function() public [payable]{
......
}

该函数有以下特点

1、匿名函数,没有参数也没有返回值。

2、在两种情况下会被调用:
        • 直接向一个合约地址转账而不加任何data(data域为空)
        • 被调用的函数不存在

3、如果转账金额不是0,同样需要声明payable,否则会抛出异常。

  • Solidity不支持多线程

        因为多个核对内存访问顺序不一致的话,执行结果可能是不确定的,这样会导致以太坊中各个节点的状态不一致。

本文参考:

http://www.tryblockchain.org/
https://www.youtube.com/watch?v=RADwCuRRoFs&list=PLnTPdMjBRmAYehJkVbAXqxO-0cc9ALC6V&index=22

https://blog.csdn.net/rejames/article/details/82884513

最后更新: 2019年03月29日 09:28

原始链接: http://yoursite.com/2019/03/27/Solidity语言基础/