以太坊智能合约开发—Solidity学习笔记

* 开发工具


* 在线文档


* 智能合约

位于以太坊区块链上特定地址的代码(其功能)和数据(其状态)的集合。
0.4.22版本之前的版本,构造函数是与合约名相同的函数,后来改为constructor;在0.7.0版本后不需要internalpublic修饰符;
一个合约最多有一个 receive 函数, 声明函数为:receive() external payable { ... },用于接受以太币;
一个合约最多有一个fallback 回退函数,在找不到指定的函数名时,就会调用fallback函数。
声明为: fallback () external [payable]fallback (bytes calldata input) external [payable] returns (bytes memory output)
如果没有receive函数时,那么fallback 函数会被执,但必须标记为 payable 才能接受以太币。
一个没有定义receive函数或fallback函数的合约,直接接收以太币(使用sendtransfer方法)会抛出一个异常, 并返还以太币。

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract Coin {
    // 关键字“public”让这些变量可以从外部读取
    address public minter;
    mapping (address => uint) public balances;

    // 轻客户端可以通过事件针对变化作出高效的反应
    event Sent(address from, address to, uint amount);

    // 这是构造函数,只有当合约创建时运行
    constructor() {
        minter = msg.sender;
    }

    function mint(address receiver, uint amount) public {
        require(msg.sender == minter);
        balances[receiver] += amount;
    }

    // Errors allow you to provide information about
    // why an operation failed. They are returned
    // to the caller of the function.
    error InsufficientBalance(uint requested, uint available);


    function send(address receiver, uint amount) public {
        if (amount > balances[msg.sender])
            revert InsufficientBalance({
                requested: amount,
                available: balances[msg.sender]
            });

        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        emit Sent(msg.sender, receiver, amount);
    }
}

* 合约可以显示地转换为address类型

address(this).balance
合约的构造函数constructor() public,可以有参数但不能重载;
合约的继承用关键词 is,可以继承多个父合约,super关键词访问父合约方法;
可以定义接口interface

* 固定大小的字节数组

值类型 bytes1,bytes2, bytes3, ...bytes32 包含从 1 到最多 32 的字节序列。
一旦被声明后,就不能修改它的长度的值,只能读取。
在确定字节大小时,使用固定大小的字节数组,gas成本更低。否则就使用bytesstring这两个引用类型

bytes3 numA=0x112233;
//大的字节数组向小的字节数组转换时,低位截断
return bytes2(numa);  //0x1122
bytes2 numB=0x1122;
//小的字节数组向大的字节数组转换时,低位补0
return bytes3(numB); //0x112200

* 动态大小的字节数组

bytes public num= new bytes(3);
return num.length;
num.push(bytes1 b1);
num[4]=bytes1 b2;
固定大小字节数组(bytes1-bytes32)不能强制转换为动态大小的字节数组(bytes)或字符串(string),反之亦然。但动态大小的字节数组(bytes)和字符串(string)可以显式互相转换。
bytes memory b=new bytes(9) 内存动态字节数组不能调整大小

* 数组

固定长度数组:int8[5] arr = [1,2,3,4,5];
固定长度数组定义之后不能再修改长度,暨不能使用push和pop方法。(ps: 0.6版本以后数组的length为只读,之前是可以修改的)

动态长度数组:int8[] arr = [1,2,3,4,5];
uint[][5] 表示5个动态数组,与C或java定义的前后顺序相反,但访问时一致。

* mapping 类似java中的hashmap

mapping (KeyType => valueType) addrs;
KeyType 可以是基本值类型、字符串,但不能为数值、字节数组或自定义类型
注意mapping目前不可迭代,即你不能枚举它们的键。如果需要迭代,则需要自己实现或引用第三方类库。

* struct 结构体

类似C语言中的结构类型,但它不能作为参数使用;只能在internal修饰的函数中作为返回值。

* delete 运算符

其实不是删除变量,而是将变量重置为默认值。数值型重置为0,枚举型也是重置为0,字符串重置为“”空,布尔型重置为false
delete 固定大小的数组,是将数组的每个元素值重置;delete动态大小数组,将数组的长度置为0;
不能直接delete mapping,但可以delete mapping中的元素。

* 状态变量(成员变量)修饰符 默认为internal

public状态变量,编译器会自动为它们生成 getter 函数,这允许其他合约读取它们的值。当在同一个合约中使用时,外部访问(例如this.x)调用 getter,而内部访问(例如x)直接从存储中获取变量值。如需要外部修改,还需要加上setter函数。修饰符的位置与java 不同的

string public name="tim";
uint8 internal id=1;
function setId(uint8 newId) public{
    id=newId;
}

private 私有修饰符,只能被当前合约访问;而internal变量可以被子合约访问,类似java中的protected;
constant 修饰符表示为常量,不能在别处修改值。

* 函数修饰符 默认为public

external
外部函数是合约接口的一部分,这意味着它们可以从其他合约和交易中调用。f不能在内部调用外部函数(即f()不工作,但this.f()工作)。
public
公共函数是合约接口的一部分,可以在内部调用,也可以通过消息调用。
internal
内部函数只能从当前合约或从它派生的合约中访问。它们不能被外部访问。由于它们没有通过合约的 ABI 暴露给外部,它们可以采用内部类型的参数,如映射或存储引用。
private
私有函数类似于内部函数,但它们在派生合约中不可见。
view
类似变量中的constant ,表示函数中不会修改状态变量的值。
pure
表示在函数中,既不允许修改状态变量值,也不允许读取状态变量值。

*数据位置(变量存储)

以太坊虚拟机有 3 个区域用来存储数据: 存储(storage), 内存(memory) 和 调用数据(calldata)
storage :存储在区块链上持久化的mapping,读写成本最高,所以尽量减少使用,状态变量必须为storage类型。
memory :存储在内存中变量,每次函数调用结束后释放,一般定义在函数内部,可以用storage注解来改写。
calldata: 读的函数参数存储区,主要用于函数的参数,使用成本最低。
0.5.0版本之后,所有复杂类型现在必须声明明确的数据位置
引用类型相同数据位置之间的赋值是传引用,而且不同数据位置的赋值是都会创建一份独立的拷贝(给状态变量的赋值总是拷贝,可能需要持久化的原因吧)。例如:
在 存储storage 和 内存memory 之间两两赋值,会创建一份独立的拷贝。
从 内存memory 到 内存memory 的赋值只创建引用, 这意味着更改内存变量,其他引用相同数据的所有其他内存变量的值也会跟着改变。

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;

contract Tiny {
    uint[] x; // x 的数据存储位置是 storage, 位置可以忽略

    // memoryArray 的数据存储位置是 memory
    function f(uint[] memory memoryArray) public {
        x = memoryArray; // 将整个数组拷贝到 storage 中,可行
        uint[] storage y = x;  // 分配一个指针(其中 y 的数据存储位置是 storage),可行
        y[7]; // 返回第 8 个元素,可行
        y.pop(); // 通过 y 修改 x,可行
        delete x; // 清除数组,同时修改 y,可行

        // 下面的就不可行了;需要在 storage 中创建新的未命名的临时数组,
        // 但 storage 是“静态”分配的:
        // y = memoryArray;
        // 下面这一行也不可行,因为这会“重置”指针,
        // 但并没有可以让它指向的合适的存储位置。
        // delete y;

        g(x); // 调用 g 函数,同时移交对 x 的引用
        h(x); // 调用 h 函数,同时在 memory 中创建一个独立的临时拷贝
    }

    function g(uint[] storage ) internal pure {}
    function h(uint[] memory) public pure {}
}

每次存储读取256位,即32字节的数据;所以变量定义的时候顺序可能会影响gas成本。

uint128 a;
uint256 b;
uint128 c;

改为以下顺序来声明会更好:

uint256 b;
uint128 a;
uint128 c;

*区块时间

通过block.timestamp获取,now在0.7版本中被删除。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容