[区块链笔记2] cryptozombies solidity知识点总结

Solidity 的代码都包裹在合约里面. 一份合约就是以太应币应用的基本模块, 所有的变量和函数都属于一份合约

状态变量是被永久地保存在合约中。也就是说它们被写入以太币区块链中. 想象成写入一个数据库。

Solidity 定义的函数的属性默认为公共。 这就意味着任何一方 (或其它合约) 都可以调用你合约里的函数。

命名规范:私有函数的名字用下划线起始

Ethereum 内部有一个散列函数keccak256,它用了SHA3版本。一个散列函数基本上就是把一个字符串转换为一个256位的16进制数字。


事件 是合约和区块链通讯的一种机制。你的前端应用“监听”某些事件,并做出反应。

这里建立事件

event IntegersAdded(uint x, uint y, uint result);

function add(uint _x, uint _y) public {
  uint result = _x + _y;
  //触发事件,通知app
  IntegersAdded(_x, _y, result);
  return result;
}

你的 app 前端可以监听这个事件。JavaScript 实现如下:

YourContract.IntegersAdded(function(error, result) { 
  // 干些事
})

以太坊有一个 JavaScript 库,名为Web3.js

以太坊区块链由 account(账户)组成,你可以把它想象成银行账户。一个帐户的余额是 以太(在以太坊区块链上使用的币种),你可以和其他帐户之间支付和接受以太币,就像你的银行帐户可以电汇资金到其他银行帐户一样。
每个帐户都有一个“地址”,你可以把它想象成银行账号。这是账户唯一的标识符

地址属于特定用户(或智能合约)的

扫描二维码关注公众号,回复: 11362964 查看本文章

注意:在 Solidity 中,功能执行始终需要从外部调用者开始。 一个合约只会在区块链上什么也不做,除非有人调用其中的函数。所以 msg.sender总是存在的。

require使得函数在执行过程中,当不满足某些条件时抛出错误,并停止执行

Solidity 并不支持原生的字符串比较, 只能通过比较两字符串的 keccak256 哈希值来进行判断

在 Solidity 中,当你有多个文件并且想把一个文件导入另一个文件时,可以使用 import 语句

Storage 变量是指永久存储在区块链中的变量。 Memory 变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除。

状态变量(在函数之外声明的变量)默认为“存储”形式,并永久写入区块链;而在函数内部声明的变量是“内存”型的,它们函数调用结束后消失。
然而也有一些情况下,你需要手动声明存储类型,主要用于处理函数内的 _ 结构体 _ 和 _ 数组 _ 时

如果我们的合约需要和区块链上的其他的合约会话,则需先定义一个 interface (接口)

OpenZeppelin 是主打安保和社区审查的智能合约库

Solidity 使用自己的本地时间单位。
变量 now 将返回当前的unix时间戳(自1970年1月1日以来经过的秒数)。
now 返回类型 uint256
Solidity 还包含秒(seconds),分钟(minutes),小时(hours),天(days),周(weeks) 和 年(years) 等时间单位。它们都会转换成对应的秒数放入 uint 中。

uint lastUpdated;

// 将‘上次更新时间’ 设置为 ‘现在’
function updateTimestamp() public {
  lastUpdated = now;
}

// 如果到上次`updateTimestamp` 超过5分钟,返回 'true'
// 不到5分钟返回 'false'
function fiveMinutesHavePassed() public view returns (bool) {
  return (now >= (lastUpdated + 5 minutes));
}

由于结构体的存储指针可以以参数的方式传递给一个 private 或 internal 的函数,因此结构体可以在多个函数之间相互传递。
遵循这样的语法:

function _doStuff(Zombie storage _zombie) internal {
  
}

用 view 标记一个函数,意味着告诉 web3.js,运行这个函数只需要查询你的本地以太坊节点,而不需要在区块链上创建一个事务(事务需要运行在每个节点上,因此花费 gas)。

注意:如果一个 view 函数在另一个函数的内部被调用,而调用函数与 view 函数的不属于同一个合约,也会产生调用成本。这是因为如果主调函数在以太坊创建了一个事务,它仍然需要逐个节点去验证。所以标记为 view 的函数只有在外部调用时才是免费的。

在数组后面加上 memory关键字, 表明这个数组是仅仅在内存中创建,不需要写入外部存储,并且在函数调用结束时它就解散了。与在程序结束时把数据保存进 storage 的做法相比,内存运算可以大大节省gas开销 – 把这数组放在view里用,完全不用花钱。

function getArray() external pure returns(uint[]) {
  // 初始化一个长度为3的内存数组
  uint[] memory values = new uint[](3);
  // 赋值
  values.push(1);
  values.push(2);
  values.push(3);
  // 返回数组
  return values;
}

一个 代币 在以太坊基本上就是一个遵循一些共同规则的智能合约——即它实现了所有其他代币合约共享的一组标准函数,例如 transfer(address _to, uint256 _value) 和 balanceOf(address _owner).

ERC721 代币, 每个代币都被认为是唯一且不可分割的。 你只能以整个单位交易它们,并且每个单位都有唯一的 ID

ERC721 规范有两种不同的方法来转移代币:

第一种方法是代币的拥有者调用transfer 方法,传入他想转移到的 address 和他想转移的代币的 _tokenId。
function transfer(address _to, uint256 _tokenId) public;

function approve(address _to, uint256 _tokenId) public;
function takeOwnership(uint256 _tokenId) public;
第二种方法是代币拥有者首先调用 approve,然后传入与以上相同的参数。
接着,该合约会存储谁被允许提取代币,通常存储到一个 mapping (uint256 => address) 里。
然后,当有人调用 takeOwnership 时,合约会检查 msg.sender 是否得到拥有者的批准来提取代币,
如果是,则将代币转移给他。

library 关键字 — 和 合约很相似,但是又有一些不同。 就我们的目的而言,库允许我们使用 using 关键字,它可以自动把库的所有方法添加给一个数据类型:
using SafeMath for uint;

assert 和 require 相似,若结果为否它就会抛出错误。 assert 和 require 区别在于,require 若失败则会返还给用户剩下的 gas, assert 则不会。所以大部分情况下,你写代码的时候会比较喜欢 require,assert 只在代码可能出现严重错误的时候使用,比如 uint 溢出。

natspec标签
@title(标题) 和 @author (作者)很直接了.
@notice (须知)向 用户 解释这个方法或者合约是做什么的。 @dev (开发者) 是向开发者解释更多的细节。
@param (参数)和 @return (返回) 用来描述这个方法需要传入什么参数以及返回什么值。

Infura 是一个服务,它维护了很多以太坊节点并提供了一个缓存层来实现高速读取。你可以用他们的 API 来免费访问这个服务。 用 Infura 作为节点提供者,你可以不用自己运营节点就能很可靠地向以太坊发送、接收信息。

Metamask 是 Chrome 和 Firefox 的浏览器扩展, 它能让用户安全地维护他们的以太坊账户和私钥, 并用他们的账户和使用 Web3.js 的网站互动

Web3.js 有两个方法来调用我们合约的函数: call and send.

call 用来调用 view 和 pure 函数。它只运行在本地节点,不会在区块链上创建事务。

send 将创建一个事务并改变区块链上的数据。你需要用 send 来调用任何非 view 或者 pure 的函数。

send 一个事务需要一个 from 地址来表明谁在调用这个函数(也就是你 Solidity 代码里的 msg.sender )
send 一个事务将花费 gas

一个 wei 是以太的最小单位 — 1 ether 等于 10^18 wei

猜你喜欢

转载自blog.csdn.net/weixin_42172261/article/details/106824976