Solidity基本语法学习4

news/发布时间2024/8/25 8:12:39

文档: https://solidity-by-example.org/
视频教程: https://www.youtube.com/watch?v=xv9OmztShIw&list=PLO5VPQH6OWdVQwpQfw9rZ67O6Pjfo6q-p

说明:

本文内容: Function Modifier, Events, Constructor, Inheritance, Shadowing Inherited State Variables, Calling Parent Contracts, Visibility, Interface

Function Modifier

Function Modifier是可以在函数调用之前和/或之后运行的代码. 可以类比AOP.

修饰符可用于:

  • 限制访问
  • 验证输入
  • 防止重入攻击. 简单来说重入攻击是利用智能合约的漏洞反复调用智能合约从而非法获利的一种攻击方式.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;contract FunctionModifier {// We will use these variables to demonstrate how to use// modifiers.address public owner;uint public x = 10;bool public locked;constructor() {// Set the transaction sender as the owner of the contract.owner = msg.sender;}// Modifier to check that the caller is the owner of// the contract.modifier onlyOwner() {require(msg.sender == owner, "Not owner");// Underscore is a special character only used inside// a function modifier and it tells Solidity to// execute the rest of the code._;}// Modifiers can take inputs. This modifier checks that the// address passed in is not the zero address.modifier validAddress(address _addr) {require(_addr != address(0), "Not valid address");_;}// 调用过一次修改成别的地址之后, 就没法修改回来了. 会报错的. function changeOwner(address _newOwner) public onlyOwner validAddress(_newOwner) {owner = _newOwner;}// Modifiers can be called before and / or after a function.// This modifier prevents a function from being called while// it is still executing.modifier noReentrancy() {require(!locked, "No reentrancy");locked = true;_;locked = false;}function decrement(uint i) public noReentrancy {x -= i;if (i > 1) {decrement(i - 1);}}
}

Events

events允许记录到以太坊区块链。
events的一些用例是:

  • 监听事件, 更新用户接口
  • 一种廉价的存储形式
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;contract Event {// Event declaration// Up to 3 parameters can be indexed.// Indexed parameters helps you filter the logs by the indexed parameterevent Log(address indexed sender, string message);event AnotherLog();function test() public {emit Log(msg.sender, "Hello World!");emit Log(msg.sender, "Hello EVM!");emit AnotherLog();}
}

要到控制台去看日志输出.

img

Inheritance

继承关系.
Solidity支持多继承Contract可以通过使用is关键字继承其他合同。
要被子智能合约覆盖的函数必须声明为虚函数(virtual)。
要重写父函数的函数必须使用关键字override
继承顺序很重要。您必须按照从most base-likemost derived的顺序列出父合约。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8;contract A {function foo() virtual  public pure returns(string memory){return "A";}
}contract B is A {function foo() virtual  override  public pure returns(string memory){return "B";}
}contract C is A {// 如果没有儿子合约(D和E)继承C了的话,就不需要virtual了。function foo() override virtual public pure returns(string memory){return "C";}
}contract D is B, C {function foo() public pure override(B, C) virtual returns(string memory){return super.foo();}
}// 注意对比, D.foo()返回的是"C", 而E.foo()返回的是"B".  
// 关键在于继承顺序, 而非override里面的顺序. 
contract E is C, B {function foo() public pure override(B, C) virtual returns(string memory){return super.foo();}
}// 但是要继承父和爷合约的话必须从左到右从大到小. 上面也说过了.
contract F is A, B {function foo() public pure override(A, B) virtual returns(string memory){return super.foo();}
}

Constructor

构造函数是可选函数,在智能合约创建时执行。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;// Base contract X
contract X {string public name;constructor(string memory _name) {name = _name;}
}// Base contract Y
contract Y {string public text;constructor(string memory _text) {text = _text;}
}// There are 2 ways to initialize parent contract with parameters.// Pass the parameters here in the inheritance list.
contract B is X("Input to X"), Y("Input to Y") {}contract C is X, Y {// Pass the parameters here in the constructor,// similar to function modifiers.constructor(string memory _name, string memory _text) X(_name) Y(_text) {}
}// Parent constructors are always called in the order of inheritance
// regardless of the order of parent contracts listed in the
// constructor of the child contract.// Order of constructors called:
// 1. X
// 2. Y
// 3. D
contract D is X, Y {constructor() X("X was called") Y("Y was called") {}
}// Order of constructors called:
// 1. X
// 2. Y
// 3. E
contract E is X, Y {constructor() Y("Y was called") X("X was called") {}
}

Shadowing Inherited State Variables

意思是隐藏继承的状态变量. 与函数不同,状态变量state variable不能通过在子契约中重新声明来重写。让我们学习如何正确地重写继承的状态变量.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8;contract A {string public name = "Contract A";function getName() public view returns(string memory) {return name;}
}// 0.6之后这种形式就被ban了. 
// contract B is A {
//     string public name = "Contract B";
// }contract C is A {constructor() {name = "Contract C";}
}

Calling Parent Contracts

父契约可以直接调用,也可以使用关键字super调用。通过使用关键字super,将调用所有的直接父契约. 前面也已经演示过了.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;/* Inheritance treeA/  \
B   C\ /D
*/contract A {// This is called an event. You can emit events from your function// and they are logged into the transaction log.// In our case, this will be useful for tracing function calls.event Log(string message);function foo() public virtual {emit Log("A.foo called");}function bar() public virtual {emit Log("A.bar called");}
}contract B is A {function foo() public virtual override {emit Log("B.foo called");A.foo();}function bar() public virtual override {emit Log("B.bar called");super.bar();}
}contract C is A {function foo() public virtual override {emit Log("C.foo called");A.foo();}function bar() public virtual override {emit Log("C.bar called");super.bar();}
}contract D is B, C {// Try:// - Call D.foo and check the transaction logs.//   Although D inherits A, B and C, it only called C and then A.// - Call D.bar and check the transaction logs//   D called C, then B, and finally A.//   Although super was called twice (by B and C) it only called A once.function foo() public override(B, C) {super.foo();}function bar() public override(B, C) {super.bar();}
}
// 顺序是C -> B -> A, 也是有讲究的. 
// D声明写成`D is C, B`就是B, C, A顺序了
[{"from": "0x540d7E428D5207B30EE03F2551Cbb5751D3c7569","topic": "0xcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab","event": "Log","args": {"0": "C.bar called","message": "C.bar called"}},{"from": "0x540d7E428D5207B30EE03F2551Cbb5751D3c7569","topic": "0xcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab","event": "Log","args": {"0": "B.bar called","message": "B.bar called"}},{"from": "0x540d7E428D5207B30EE03F2551Cbb5751D3c7569","topic": "0xcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab","event": "Log","args": {"0": "A.bar called","message": "A.bar called"}}
]

Visibility

函数和状态变量必须声明它们是否可以被其他智能合约访问
函数可以声明为:

  • public---任何合约和账户都可以调用.
  • private---只能在本合约内用.
  • internal---同一合约和儿子合约可以调用.
  • external---仅其他契约和帐户可以调用
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;contract Base {// Private function can only be called// - inside this contract// Contracts that inherit this contract cannot call this function.function privateFunc() private pure returns(string memory){return "private function called";}function testPrivateFunc() pure public returns(string memory){return string(abi.encodePacked(privateFunc(), "test"));}// Internal function can be called// - inside this contract// - inside contracts that inherit this contractfunction internalFunc() internal pure returns(string memory){return "internal function called";}function testInternalFunc() public pure virtual returns(string memory){return string(abi.encodePacked(internalFunc(), "test"));}function publicFunc() public pure returns(string memory){return "public function called";}// External functions can only be called// - by other contracts and accountsfunction externalFunc() external pure returns(string memory){return "external function called";}// This function will not compile since we're trying to call// an external function here.// function testExternalFunc() public pure returns (string memory) {//     // 报错: DeclarationError: Undeclared identifier.//     return externalFunc();// }string private privateVar = "my private variable";string internal internalVar = "my internal variable";string public publicVar = "my public variable";// State variables cannot be external so this code won't compile.// 报错: ParserError: Expected identifier but got 'external'// string external externalVar = "my external variable";
}contract Child is Base {// Inherited contracts do not have access to private functions// and state variables.// 报错: DeclarationError: Undeclared identifier.// function testPrivateFunc() public pure returns (string memory) {//     return privateFunc();// }function testInternalFunc() public pure override returns(string memory) {return string(abi.encodePacked(internalFunc(), " child test"));}
}

结果
注意这些函数都是用public或者external修饰的.

Interface

可以通过声明接口interface与其他合约进行交互。
interface特点:

  • 没有具体实现
  • 可以从其他接口继承
  • 所有声明的功能必须是external修饰的
  • 无法声明构造函数
  • 无法声明状态变量
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;// Counter合约,用于计数
contract Counter {uint public count;// 增加计数的函数function increment() external {count += 1;}
}// 计数器接口,定义了获取计数和增加计数的函数
interface ICounter {function count() external view returns (uint);function increment() external;
}// MyContract合约,包含与ICounter合约交互的函数
contract MyContract {// 通过传递的_counter地址调用ICounter合约的increment函数function incrementCounter(address _counter) external {ICounter(_counter).increment();}// 通过传递的_counter地址调用ICounter合约的count函数function getCount(address _counter) external view returns(uint){return ICounter(_counter).count();}
}// UniswapV2Factory接口,用于获取Uniswap交易对的地址
interface UniswapV2Factory {function getPair(address tokenA,address tokenB) external view returns(address pair);
}// UniswapV2Pair接口,用于获取Uniswap交易对的储备量信息
interface UniswapV2Pair {function getReserves()external view returns(uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}// UniswapExample合约,用于获取Uniswap交易对的储备量信息
contract UniswapExample {// Uniswap工厂合约地址address private factory = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;// DAI代币地址address private dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;// WETH代币地址address private weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;// 获取Uniswap交易对的储备量信息function getTokenReserves() external view returns (uint, uint){// 获取DAI-WETH交易对地址address pair = UniswapV2Factory(factory).getPair(dai, weth);// 调用UniswapV2Pair接口获取储备量信息(uint reserve0, uint reserve1, ) = UniswapV2Pair(pair).getReserves();return (reserve0, reserve1);}
}

uniswap还没研究过, 在Remix用的时候是报错的.
不过Counter的用法倒是清楚.
输出
注意填写的address, 是Counter合约的地址.
用右边Counter合约的地址执行左边的MyCounterincrementCounter, 会增加右边Counter合约的count.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.liansuoyi.cn/news/53177824.html

如若内容造成侵权/违法违规/事实不符,请联系连锁易网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

面对每月更新的数据源

问题:表1的数据每月更新,填到表2时不能覆盖掉原有数据。 思路1: 数据不在原列上更新,而是新增一列。如下图,当月数据填在T列,下月数据填在U列,以此类推。 使用公式:=SUMIF(表1!A:A,D2,表1!B:B)表1更新前公式一列需要粘贴成值思路2: 在表1建一个新表,每月将数据以粘贴…

2023-2024-1 20232407 《网络》第5周学习总结

教材学习内容总结教材学习中的问题和解决过程 问题1:什么是sybil攻击? 问题1解决方案:询问chatgpt 问题2:除计算机技术外,还有哪些领域需要协同工作来更好地保证信息内容的安全 问题2解决方案:询问chatgpt基于AI的学习感悟 人工智能的发展也为内容安全提供了新的解决方案…

CentOS的GPT分区+LVM挂载

为突破MBR分区限制(最大卷:2T,最多4个主分区或3个主分区加一个扩展分区)常常以GPT分区方式(突破MBR 4个主分区限制,每个磁盘最多支持128个分区,支持大于2T的分区,最大卷可达18EB)新建分区并挂载,下面记录自己常用的GPT+LVM的方式挂载新的硬盘的方式。 1.查看硬盘标签…

RISC-V 环境搭建问题----1

在此记录一下搭建开源Vivado-risc-v项目时所遇到的一些问题本来已经弄好的差不多了,最后一看,下载的别人网盘的,版本落后了,只支持到vivado 2022.1....只好重新拉一下最新的,又踩雷无数。1.wls2 进行git clone时连接拒绝原文:Ubuntu20.4 WSL2 无法访问github终极解决方案…

linux基础知识

目录1.linux了解(1)界面基础2.文件管理(1)文件目录查看(2)文件目录管理ls :列出目录cd :切换目录pwd :显示目前所在的目录mkdir/rm:新建与删除文件夹(3)rz / sz:文件上传与下载(4)unzip: 文件解压与压缩(5)文件内容查看1)cat:由第一行开始显示文件内容2)nl:由…

深度解读DBSCAN聚类算法:技术与实战全解析

探索DBSCAN算法的内涵与应用,本文详述其理论基础、关键参数、实战案例及最佳实践,揭示如何有效利用DBSCAN处理复杂数据集,突破传统聚类限制。关注TechLead,分享AI全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验…

Markdown编辑器

Markdown编辑器 Typora a markdown editor, markdown reader. 官网下载地址

Bounded Value

Bounded Value####################QQ 3087438119

汽车传感器类型杂谈

汽车传感器类型杂谈 在某种程度上,车辆传感器是车辆的感觉器官。作为电子管理系统的基本组成部分,它们必须记录物理或化学变量,并将其转换为电信号… 目录 •车辆传感器的类型 o 1.位置传感器(距离/角度传感器)- o 2.速度和速度传感器 o 3.加速度传感器 o 4.温度传感器 o …

触摸屏的“坎坷成长史”

触摸屏的“坎坷成长史” 2023-04-30 18:25智次方 资料来源:中兴文档 作者:中兴文档 物联网智库 转载导读触摸屏的历史,比你想象中的要更“沧桑”。 我们每个人都会在闲暇之余玩手游、刷微博、短视频或者是用pad追个剧。文档君也不例外,每晚睡前必刷手机。手指在小小的屏幕…

自组织临界状态

多种地震模式的学术思想百年进化的总趋势是由震源到动力系统。在地球系统科学框架下,基于五十年来大地测量学对大陆变形的精确观测和动力学的初步研究,以及对地球物理学、地质学、岩石力学、复杂动力学系统理论等的交叉研究,追寻了由地球形成至大陆现今地壳运动的演化进程,…

Netty内置的http报文解码流程

netty解码 netty通过内置处理器HttpRequestDecoder和HttpObjectAggregator对Http请求报文进行解码之后,Netty会将Http请求封装成一个FullHttpRequest实例,然后发送给下一站。Netty内置的与Http请求报文相对应的类大致有如下几个: (1)FullHttpRequest:包含整个Http请求的信…

Unicode编码解码

一、Unicode概述 Unicode是一种字符编码标准,旨在解决不同字符集之间的兼容性问题。它为全球所有语言提供了一种统一的编码方式,使得各种字符能够在计算机系统中正确显示和处理。Unicode字符集包含了世界上几乎所有的字符,包括中文字符、英文字符、数字、特殊符号等。 Unico…

【项目学习】谷粒商城学习记录5 - 检索服务

【项目学习】谷粒商城学习记录5 - 检索服务1、搭建页面环境search模块添加thymeleaf依赖<!-- thymeleaf --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId> </depe…

linux安装telnet远程

安装telnet远程 1.RPM安装yum install -y telnet* xinetd2.启动服务// 开启xinetd服务 systemctl restart xinetd // xinetd开机自启 systemctl enable xinetd // 开启telnet.socket服务 systemctl restart telnet.socket //telnet.socket开机自启 systemctl enable telnet.soc…

BLOG-3

前言: 第七次题目集共有四道题目。其中有两道考察HashMap的检索与排序功能,一道考察多态的运用,最重要的一道是成绩计算系统-2。 第八次题目集共有五道题目,考察了ArrayList容器的排序方法、身份证排序方法、自定义接口、覆盖等知识,还有成绩计算系统-3。该系统是成绩计算…

内存可见于内存可用

在GPU执行过程中有责任保证接下来访问的这块内存是保证有效的,也就是确保先前写入的数据对目标单元可见。简单介绍一下GPU Cache体系,平时听得比较多的是CPU Cache,但是GPU同样有着自己的Cache体系。 如下图所示,在这里可以看GPU同样是有着L1/L2 Cache的架构。 那么在GPU中…

CF1842B Tenzing and Books 题解

题意:思路: 或运算的性质:当 $ u $ 某一位的数字变为 $ 1 $ ,这一位永远都不会变为 $ 0 $。 因此,当某个栈的栈顶元素 $ v_i $ 满足 $ v_i | x = x $ 时,取出该栈顶元素 $ v_i $ ,令 $ u = u | v_i $ ;反之,不再从该栈取出元素。 不断重复以上过程,当 $ u = x $ 时,…

Qt6 c++教程2 Qt Creator简介

2 Qt Creator简介 Qt Creator是Qt自带的集成开发环境(IDE),用于跨平台应用程序开发。在本章中,您将学习Qt Creator集成开发环境的基础知识,并了解集成开发环境的用户界面 (UI)。我们还将了解如何在 Qt Creator中创建和管理项目。本Qt 模块包括使用Qt Creator开发一个简单的…
推荐文章