1、回退函数
fallback():当调用的函数不存在或者直接向合约发送主币的时候调用fallback函数。
receive():不能接受数据,仅向合约发送主币时触发
// SPDX-License-Identifier:MIT
pragma solidity ^0.8.7;
contract Fallback {
event Log(string func,address sender , uint value ,bytes data);
fallback() external payable {
emit Log("fallback", msg.sender, msg.value,msg.data);
}
//receive 不接受数据
receive() external payable {
emit Log("receive", msg.sender, msg.value, "");
}
}
2、发送ETH
可以通过send、transfer和call进行主笔发送。
send返回true和false来确定是否发送失败;
transfer返回revert来确定是否发送失败;
call返回ture和false,如果接收地址有信息时可以返回信息data
// SPDX-License-Identifier:MIT
pragma solidity ^0.8.7;
contract SendETH {
constructor() payable{}
receive() external payable {}
function sendViaTransfer(address payable _to) external payable {
_to.transfer(123);
}
function sendViaSend(address payable _to) external payable{
bool sent = _to.send(123);
require(sent,"send failde");
}
//发送所有的gas
function sendViaCall(address payable _to) external payable{
(bool success,) = _to.call{value: 123}("");
require(success, "send failed")
}
}
3、小案例:建立简单钱包合约
// SPDX-License-Identifier:MIT
pragma solidity ^0.8.7;
contract SimpleWallet{
address payable public owner;
constructor(){
owner = payable(msg.sender);
}
receive() external payable{}
function withdraw(uint amount) public{
require(msg.sender == owner);
owner.transfer(amount);
}
function getBalance() public view returns (uint){
return address(this).balance;
}
}
4、调用其他合约
输入其他合约的地址,之后可以直接把其他合约当作类型进行使用。还可以把类型当作直接输入的变量的类型进行传入。
// SPDX-License-Identifier:MIT
pragma solidity ^0.8.7;
contract CallTestContract {
//为调用函数传参
function setX(address _test, uint _x) external {
TestContract(_test).setX(_x);
}
//获取从方法得到的参数
function getX(address _test) external view returns(uint x){
return x = TestContract(_test).getX();
}
//传参并发送主币
function setXandReceiveEther(address _test, uint _x) external payable {
TestContract(_test).setXandReceiveEther(_x);
}
//获取两个参数
function getXandValue(address _test) external returns(uint x,uint value) {
(x,value) = TestContract(_test).getXandValue();
}
}
contract TestContract {
uint public x;
uint public value = 123;
function setX(uint _x) external {
x = _x;
}
function getX() external view returns (uint) {
return x;
}
function setXandReceiveEther(uint _x) external payable {
x = _x;
value = msg.value;
}
function getXandValue() external view returns (uint,uint) {
return(x,value);
}
}
5、接口合约
不知道另一个合约的源代码或者代码量特别大时,可以使用接口合约。
// SPDX-License-Identifier:MIT
pragma solidity ^0.8.7;
contract Counter {
uint public count;
function inc() external {
count += 1;
}
function dec() external {
count -= 1;
}
}
//在接口合约中调用了两个合约的函数
interface ICounter {
function count() external view returns (uint);
function inc() external;
}
contract CallInterface {
uint public count;
function examples(address _counter) external{
ICounter(_counter).inc();
count = ICounter(_counter).count();
}
}
6、低级调用 Call
使用Call直接根据合约地址调用合约功能。
// SPDX-License-Identifier:MIT
pragma solidity ^0.8.7;
contract TestCall{
string public message;
uint public x;
event Log(string message);
fallback() external payable{
emit Log("fallback was called");
}
function foo(string memory _message, uint _x) external payable returns (bool,uint){
message = _message;
x = _x;
return(true,999);
}
}
contract Call{
bytes public data;
function callFoo(address _test) external {
//使用call调用目标地址的函数,返回是否调用成功,以及一个返回值,该返回值转载了所有返回的数据
//可以携带一定数量的主币和gas进行调用
(bool success, bytes memory data) = _test.call{value: 111, gas:5000}(abi.encodeWithSignature(
"foo(string,uint256)","call foo",123
));
require(success,"call failed");
}
function callDoesNotExit(address _test) external{
(bool success,) = _test.call(abi.encodeWithSignature("DONTEXIST(string,uint)"));
require(success,"call failed");
}
}
7、委托调用:
用于观测其他合约的交互。
例如:A向B发送100wei,B委托调用C,站在C的视角能够看到A向B发送100wei,但C自身的状态变量不发生改变。
委托调用可以用来实现合约升级。
委托调用执行函数后的值在委托调用合约中修改。
// SPDX-License-Identifier:MIT
pragma solidity ^0.8.7;
contract TestDelegateCall {
uint public num;
address public sender;
uint public value;
function setVars(uint _num) external payable {
num = _num;
sender = msg.sender;
value = msg.value;
}
}
contract DelegateCall {
uint public num;
address public sender;
uint public value;
function setVars(address _test,uint _num) external payable{
//使用签名进行编码
// _test.delegatecall(
// abi.encodeWithSignature("setVars(uint256)",_num)
// );
//使用selector进行编码
(bool success,bytes memory data) = _test.delegatecall(
abi.encodeWithSelector(TestDelegateCall.setVars.selector, _num)
);
require(success,"delegatecall failed");
}
}
8、工厂合约
用于生成新的合约
// SPDX-License-Identifier:MIT
pragma solidity ^0.8.7;
contract Account {
address public bank;
address public owner;
constructor(address _owner) payable{
bank = msg.sender;
owner = _owner;
}
}
contract AccountFactory {
Account[] public accounts;
address public owner;
constructor() payable{
owner = msg.sender;
}
function createAccount(address _owner,uint amount) external {
//account 变量记录了新建立的账户的地址,通过增加{value}来向新创建的合约中发送主币。
//在构建包含主币的合约前应当向账户工厂发送一定数量的主币
Account account = new Account{value:amount} (_owner);
//构建accounts以记录所有由该合约生成的合约
accounts.push(account);
}
function Val() external view returns(uint val){
return address(this).balance;
}
}
9、库合约
将一些常用的算法抽象出来,形成数据库,以后可以直接调用,从而避免代码的重复使用。
// SPDX-License-Identifier:MIT
pragma solidity ^0.8.7;
library Math{
function max(uint x,uint y) internal pure returns (uint){
return x>=y ? x:y;
}
}
contract Test{
function testMax(uint x,uint y) external pure returns (uint){
return Math.max(x,y);
}
}
library ArrayLib {
function find(uint[] storage arr,uint x) internal view returns (uint){
for (uint i =0;i<arr.length;i++){
if(arr[i] == x){
return x;
}
}
revert("not found");
}
}
contract TestArray{
using ArrayLib for uint[];
uint[] public arr = [3,2,1];
function testFind() external view returns (uint i){
// return ArrayLib.find(arr,2);
return arr.find(2);
}
}
10、哈希算法
通常用于签名运算和获取特定ID
在对数据进行打包时,如果使用api.encodePacked方法,可能会造成哈希碰撞(加密内容不相同但哈希运算结果相同)的问题。
两种打包方法:
abi.encodePacked()
abi.encode()
// SPDX-License-Identifier:MIT
pragma solidity ^0.8.7;
contract HashFunc{
function hash1(string memory text ,uint num ,address addr) external pure returns(bytes32){
return keccak256(abi.encodePacked(text,num,addr));
}
function hash2(string memory text ,uint num ,address addr) external pure returns(bytes32){
return keccak256(abi.encode(text,num,addr));
}
}
我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He
所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
在Ruby类中,我重写了三个方法,并且在每个方法中,我基本上做同样的事情:classExampleClassdefconfirmation_required?is_allowed&&superenddefpostpone_email_change?is_allowed&&superenddefreconfirmation_required?is_allowed&&superendend有更简洁的语法吗?如何缩短代码? 最佳答案 如何使用别名?classExampleClassdefconfirmation_required?is_a
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
可能已经问过了,但我找不到它。这里有2个常见的情况(对我来说,在编程Rails时......)用ruby编写是令人沮丧的:"astring".match(/abc(.+)abc/)[1]在这种情况下,我得到一个错误,因为字符串不匹配,因此在nil上调用[]运算符。我想找到的是比以下内容更好的替代方法:temp="astring".match(/abc(.+)abc/);temp.nil??nil:temp[1]简而言之,如果不匹配,则简单地返回nil而不会出错第二种情况是这样的:var=something.very.long.and.tedious.to.writevar=some
我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。
我正在学习Ruby的基础知识(刚刚开始),我遇到了Hash.[]method.它被引入a=["foo",1,"bar",2]=>["foo",1,"bar",2]Hash[*a]=>{"foo"=>1,"bar"=>2}稍加思索,我发现Hash[*a]等同于Hash.[](*a)或Hash.[]*一个。我的问题是为什么会这样。是什么让您将*a放在方括号内,是否有某种规则可以在何时何地使用“it”?编辑:我的措辞似乎造成了一些困惑。我不是在问数组扩展。我明白了。我的问题基本上是:如果[]是方法名称,为什么可以将参数放在括号内?这看起来几乎——但不完全是——就像说如果你有一个方法Foo.d
我的工作要求我为某些测试自动生成电子邮件。我一直在四处寻找,但未能找到可以快速实现的合理解决方案。它需要在outlook而不是其他邮件服务器中,因为我们有一些奇怪的身份验证规则,我们需要保存草稿而不是仅仅发送邮件的选项。显然win32ole可以做到这一点,但我找不到任何相当简单的例子。 最佳答案 假设存储了Outlook凭据并且您设置为自动登录到Outlook,WIN32OLE可以很好地完成此操作:require'win32ole'outlook=WIN32OLE.new('Outlook.Application')message=
本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决