在讲修改器(modifier)之前,我们使用前面几篇文章所学到的知识来实现一个简单的 token 类合约。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract InheritanceModifierExample {
mapping(address => uint) public tokenBalance;
//拥有者
address owner;
uint tokenPrice = 1 ether;
constructor() {
owner = msg.sender;
tokenBalance[owner] = 100;
}
function createNewToken() public {
//使用 require 检查是不是合约拥有着
require(msg.sender == owner, "You are not allowed");
tokenBalance[owner]++;
}
function burnToken() public {
require(msg.sender == owner, "You are not allowed");
tokenBalance[owner]--;
}
function purchaseToken() public payable {
require((tokenBalance[owner] * tokenPrice) / msg.value > 0, "not enough tokens");
tokenBalance[owner] -= msg.value / tokenPrice;
tokenBalance[msg.sender] += msg.value / tokenPrice;
}
function sendToken(address _to, uint _amount) public {
require(tokenBalance[msg.sender] >= _amount, "Not enough tokens");
tokenBalance[msg.sender] -= _amount;
tokenBalance[_to] += _amount;
}
}

我们拷贝部署合约的 account 地址0x5B38Da6a701c568545dCfcB03FcB875f56beddC4。
切换成其他 account ,也拷贝出地址 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2。


查看 account Ether 是否正确,复制 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2,将其填入 tokenBalance 的输入栏,看看 Ether 是否为1。

我们再来看看该账户 burn with Account会发生什么样的状况呢?

从上述这个简单的代币类合约,聪慧如您,想必是看出它的不足了。
没错,就是上面合约中的函数都有类似的 require 语句,作为开发者的您会将这些 require 语句抽取到一个函数中,但在 Solidity 却引入了一种特别的函数——修改器(modifier)。
修改器(modifier)在 Solidity 中是一种特殊类型的函数,用于修改其它函数的行为。例如,开发人员可以使用修改器来检查在允许函数执行之前是否满足某个条件。
修改器(modifier)与函数类似,因为它们可以接受参数并有一个返回类型。修改器(modifier)也可以被链在一起,这意味着你可以在一个函数上有多个修改器(modifier)。
然而,修改器(modifier)只能修改合约逻辑,不能修改合约的存储,包括结构。修改器(modifier)减少了开发者必须编写模板代码的数量,并且可以使您的 Solidity 代码更加可读。
多个修改器(modifier)由空格分隔。修改器(modifier)的顺序很重要。列表中的第一个修改器(modifier)将被首先执行,第二个修改器(modifier)将被第二次应用,以此类推。
例如,如果您有一个修改器(modifier)检查用户是否经过认证,另一个修改器(modifier)检查用户是否被授权查看某个资源,那么这些修改器(modifier)的应用顺序将决定用户是否能够查看该资源。
修改器(modifier)的不同类型Solidity修改器(modifier)有四大类:闸门检查、先决条件、过滤器和防止重入攻击。
它在允许一个函数执行之前检查某个条件是否为真。
例如,您可能有一个允许用户从他们的账户中取钱的函数,但在函数执行之前,开发者可能想检查用户的账户中是否有足够的钱来进行取款。这种检查被认为是一个门检查修改器。
另一个闸门检查的例子是,在允许用户查看某个资源之前,检查用户是否经过认证的函数。
它为一个函数的执行设置了环境,而不是检查某个条件是否为真。
例如,一个 Solidity 开发者可能会使用一个需要一定数量的Ether来执行函数。在这种情况下,先决条件将是设置Ether平衡的函数。
它检查某个条件是否为真,如果是,则允许函数执行。如果条件不为真,那么该函数将不会执行。
与闸门检查不同,即使条件为真,也不会自动允许函数执行,而过滤器将允许函数在条件为真时执行。
递归攻击是一种攻击类型,恶意行为者试图通过递归调用多次执行一个函数,以利用它。
例如,想象一下,您有一个允许用户从他们的账户中提款的函数。一个重入式攻击者可能会试图多次调用该函数,以提取比他们账户中实际拥有的更多的钱。
为了防止重入式攻击,您可以使用一个修改器来检查该函数是否被递归调用。如果是,那么该函数将不会执行。
require 经常与修改器互换使用,因为它们都允许您在一个函数执行之前检查某个条件是否为真。如果指定的条件不为真,那么编译器就会抛出一个错误。
例如,下面的语句使用 require 关键字,以便只有所有者才能与一个函数进行交互。
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
1、修改器(modiffier) 可用于为一个函数的执行设置环境(如先决条件的情况下)
2、require 只能用于检查某个条件是否为真 3、修改器(modiffier)` 可以被重写
4、要求不能被覆盖
修改器(modiffier) 重写?virtual关键字可以用来表示可以在派生合约中override(重写)。
例如,一个带有修改器(modifier)的合约,而派生合约继承自它。
假使,基合约中的修改器(modifier)被标记了virtual,那么它便可以在派生合约中被override(重写)。
继承可以让您扩展合约的属性,在修改器(modifier)的上下文中,继承允许您添加新的(modifier),或覆盖现有的(modifier)。
下面的简单实现演示了继承和修改器如何一起工作。
contract A {
modifier X virtual {
}
}
contract B is A {
modifier X override {
}
}
在这个例子中,合约 B 继承了合约 A,两个合约都有一个叫做 X的修改器。然而,在合约 B 中,该修饰语被标记为override,这表明它覆盖了合约 A 中的修改器。
当使用一个修改器时,您首先需要在合约中定义修改器函数。修改器使用一个特殊的符号_,只有当修改器的条件得到满足时,才会插入函数体。
下面的合同演示了如何使用一个修改器。
contract Owner {
address public owner = msg.sender;
modifier onlyOwner {
require(msg.sender == owner);
_;
}
modifier costs(uint price) {
if (msg.value >= price) {
_;
}
}
}
在上面的例子中,该合约有两个修改器:onlyOwner costs。
第一个修改器检查msg.sender是否是合约的所有者,第二个修改器检查msg.value是否大于或等于某个价格。
这两个修饰符都可以用在合同中的任何函数上。
_ 放在哪里?_ 被称为合并通配符。它将函数代码与 _ 所在的修改器代码合并。
换句话说,函数的主体(修改器所连接的)将被插入修改器的定义中出现 _ 的地方。
一个修改器必须在其主体内有 _ 才能执行。它是强制性的(如果不是这样的话,Solidity 会抛出一个错误吗)。
您写将 _ 符号的地方将决定该函数是在修改器代码之前、之间还是之后执行。
modifier SomethingBefore {
require(/* check something first */);
_; // 继续执行功能
}
modifier SomethingAfter {
_; // 先运行函数
require(/* then check something */)
}
如上面的例子所示,您可以把 _ 放在修饰语体的开头、中间或结尾。
在实践中,(特别是在您真正了解修改器的工作原理之前),最安全的使用模式是将 _ 放在最后。在这种情况下,修改器的作用是一致的验证检查,所以要先检查一个条件,然后再继续。下面的代码片段显示了这个例子。
function isOkay() public view returns(bool) {
// 做一些验证检查
return true;
}
function isAuthorised(address _user) public view returns(bool) {
// 逻辑检查以及账户授权
return true;
}
modifier OnlyIfOkAndAuthorised {
require(isOkay());
require(isAuthorised(msg.sender));
_;
}
修改器也可以接受参数。像函数一样。
modifier Fee (uint _fee) {
if (msg.value >= _fee) {
_;
}
}
使用上面的例子,您可以确保调用您的一个合约函数的用户(或合约)已经发送了一些Ether来支付预先要求的费用。
让我们用一个简单的例子来说明,这个合约就像一个金库。
您想确保每个想取出储存在合约金库中的钱的用户都要向合约支付最低2.5%的费用。
一个带有参数的修改器可以模拟这种行为。请看下面的代码。
// SPDX-License-Idendifier: GPL-3.0
pragma solidity ^0.8.0;
contract Vault {
modifier fee(uint _fee) {
if (msg.value != _fee) {
revert("You must pay a fee to withdraw your ethers");
} else {
_;
}
}
function deposit(address _user, uint _amount) external {
// ...
}
function withdraw(uint _amount) external payable fee(0.025 ether) {
// ...
}
}
修改器参数允许使用任意表达式,在这种情况下,所有从函数中可见的符号都在修改器中可见。
多个修改器可以应用到一个函数,您可以这样做。
contract OwnerContract {
address public owner = msg.sender;
uint public creationTime = now;
modifier onlyBy(address _account) {
require(
msg.sender == _account,
"Sender not authorized.
);
_;
}
modifier onlyAfter(uint _time) {
require(
now >= _time,
"Function called too early."
);
_;
}
function disown() public onlyBy(owner) onlyAfter(creationTime + 6 weeks) {
delete owner;
}
}
修改器将按照它们被定义的顺序执行,所以从左到右。所以在上面的例子中,该函数将在运行前检查以下条件。
onlyBy(...) : 调用合同的地址是否为所有者?
onlyAfter(...) : 是否有超过6周的时间是该人的所有者?
如果您的合约持有一个枚举类型的状态变量,您可以通过传递一个可用的选项作为修改器的参数来检查它持有的值。
enum State { Created, Locked, Inactive }
State state;modifier isState(State _expectedState) {
require(state == _expectedState);
_;
}
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭11年前。Improvethisquestion我不经常使用ruby-通常它加起来相当于每两个月或更长时间编写一次脚本。我的大部分编程都是使用C++进行的,这与ruby有很大不同。由于我与ruby之间的差距如此之大,我总是忘记语言的基本方面(比如解析文本文件和其他简单的东西)。我想每天练习一些基本的东西,我想知道是否有一些我可以订阅的网站,并且会向我发送当天的Ruby问题或类似的东西。有人知道这样的站点/Internet服务吗?
假设我有一个名为Product的模型,其中有一个名为brand的字段。假设brand的值以this_is_a_brand格式存储。我可以在模型(或其他任何地方)中定义一个方法,允许我在调用brand之前修改它的值吗?例如,如果我调用@product.brand,我想得到ThisisaBrand,而不是this_is_a_brand。 最佳答案 我建议使用方括号语法([]和[]=)而不是read_attribute和write_attribute。方括号语法更短并且designedtowraptheprotectedread/writ
前面一篇关于智能合约翻译文讲到了,是一种计算机程序,既然是程序,那就可以使用程序语言去编写智能合约了。而若想玩区块链上的项目,大部分区块链项目都是开源的,能看得懂智能合约代码,或找出其中的漏洞,那么,学习Solidity这门高级的智能合约语言是有必要的,当然,这都得在公链``````以太坊上,毕竟国内的联盟链有些是不兼容Solidity。Solidity是一种面向对象的高级语言,用于实现智能合约。智能合约是管理以太坊状态下的账户行为的程序。Solidity是运行在以太坊(Ethereum)虚拟机(EVM)上,其语法受到了c++、python、javascript影响。Solidity是静态类型
在尝试构建Rubygem(使用Bundler)时,我倾向于使用Bundler提供的REPL测试代码——可通过bundleconsole访问。有什么方法可以重新加载整个项目吗?我最终再次加载单个(更改的)文件以测试新更改。 最佳答案 以下hack适用于我的一个相对简单的gem和Ruby2.2.2。我很想看看它是否适合你。它做出以下假设:您具有传统的文件夹结构:一个名为lib/my_gem_name.rb的文件和一个文件夹lib/my_gem_name/,其中包含任何文件/文件夹结构。您要重新加载的所有类都嵌套在您的顶级模块MyGemN
目录1、yum安装mysql修改密码(1)在mysql里面修改(2)第二种方式,利用mysqladmin修改密码2、没有密码,登录mysql修改密码3、mysql的安全设置1、yum安装mysql在CentOS中默认安装有MariaDB(MySQL的一个分支),安装完成之后可以直接覆盖MariaDB。rpm-qa|grepmariadb查询是否安装了mariadbrpm-e--nodepsmariadb-libs-5.5.60-1.el7_5.x86_64卸载mariadwgethttp://dev.mysql.com/get/mysql57-community-release-el7-11.
目录POSIXAPI大集合五元组三次握手的过程,内核协议栈分析listen函数DDOS攻击,洪水攻击DDOS攻击的应对措施数据发送 怎么保证顺序?如何保证包地顺序到达(序号+确认应答机制+重传)TCP断开连接的过程问题1.大量的CLOSE_WAIT+FIN_WAIT2是为啥?time_wait状态存在的原因?POSIXAPI大集合五元组(sip,sport,dip,dport,protocol)三次握手的过程,内核协议栈分析内核协议栈中是有内核数据结构的. 我们send/write数据,都是先发送到内核协议栈中,然后由内核协议栈封装发送到物理介质中传输到对端的对端的接收过程也是经有内核协议栈
我有一个Ruby应用程序,我需要修改现有的zip文件。我想在内存中构建zip文件并流回字节,而无需将文件写入文件系统。如果我最终在Heroku上托管它,我认为我无法写入文件系统。有谁知道这样做的方法吗?我看了Zip::ZipFile但看起来它总是想写入文件系统。我想“基于java实现”我将能够只获取压缩文件的字节,这可以在java中完成,但我看不到这样做的方法。编辑:我要问的与此基本相同,但针对Ruby而不是Python:Functiontocreatein-memoryzipfileandreturnashttpresponse 最佳答案
我想检查是否正在Rails的before_save回调中创建模型。我还想检查它是否已被修改(更新时)。谢谢 最佳答案 您可以使用new_record?看看你是否有一个全新的对象和changed?查看是否有任何变化:before_save:pancakesdefpancakesifnew_record?#Notinthedatabaseyet.elsifchanged?#Alreadyexistsbutithasunsavedchanges.endend 关于ruby-on-rails-检
鉴于以下哈希结构,我想遍历该结构并使用“链接”键对所有值进行修改:{"page_id":"12345","link_data":{"message":"testmessage","link":"https://www.example.com","caption":"https://www.example.com","child_attachments":[{"link":"http://www.example.com","name":"test","description":"test","picture":"https://fbcdn-creative-a.akamaihd.net/