Ethereum笔记(一)

Ethereum笔记(一)

一、核心概念

1、账户

(1)基本概念

地址(Address):用20字节来表示它的地址;

状态(State)

(2)账户分类

  • 外部账户(EOA):外部拥有的账户,是通过私钥来控制,没有相关联的代码;

  • 合约账户:当我们把合约的字节码部署到区块链之后,就会有一个特定的地址来标识这个合约,这个地址就是表现为一个合约的账户;

2、一个常见警告

如果合约里写有构造函数

contract Hello {

function Hello() public {



}

}

如果是使用了新的版本编译器。可能会报错

Warning: Defining constructors as functions with the same name as the contract is deprecated. Use “constructor(…) { … }” instead.

最新版语言编译需要这么写:

contract Hello {

constructors() public {



}

}

3、以太币单位

最小单位:1 Wei

10^9 Wei = 1 Gwei

10^12 Wei = 1 szabo(萨博)

10^15 Wei = 1 finey(芬尼)

10^18 Wei = 1 Ether

4、标准代币接口的实现和标准代币实现

pragma solidity ^0.4.0;



//标准代币的接口

contract ERC20Interface{

string public name;//代币的名字

string public symbol;//代币的简写

uint8 public decimals;//代币的小数点后位数,一个代币最多可以分成多少份,如果一个代币可以切分为10份,那么小数点后位数就是1位(即0.1)

uint256 public totalSupply;//代币的供应量(总共发行了多少代币)

//获取拥有的账户余额

function balanceOf(address _owner) public view returns (uint256 balance);

//交易代币:向地址(_to)发送数量为_value的代币,发送成功则返回true

function transfer(address _to,uint256 _value) public returns(bool success);

//将数量为_value的代币从地址_from交易到地址_to,而且该函数需要启用Transfer事件;该函数一般用于取款(提款)的流程,允许合约代表你进行交易;

function transferFrom(address _from,address _to,uint256 _value) public returns(bool success);

// 允许_spender这个地址的账户从你的账户提款,直到达到你设置的限额_value(说白了就是允许别人操作你的账户,但是操作的金额是有限的)

function approve(address _spender,uint256 _value) public returns(bool success);

//返回_spender这个地址的账户仍允许从_owner这个地址的账户提款多少(即别人还允许从你的账户上花多少钱)

function allowance(address _owner,address _spender) public view returns(uint256 remaining);

//交易事件:在代币交易的时候必须触发该事件,且包括交易数量为0个代币的情况(如在调用transfer和transferFrom函数就必须触发该事件)

event Transfer(address indexed _from, address indexed _to,uint256 _value);

//委托事件:在调用approve函数的时候必须触发Approval事件

event Approval(address indexed _owner,address indexed _spender,uint256 _value);

// 触发事件了就能对事件进行监听,类似于回调

}



contract ERC20 is ERC20Interface{

//类似于字典(键=>值组合)

mapping(address=>uint256) public balanceOf;

mapping(address=>mapping(address=>uint256)) internal allowed;



constructor () public{

name = "YuanToken";

symbol = "Yuan";

decimals = 0;//小数点后位数为0,即一个代币最多只能分一份

totalSupply = 1000000;

balanceOf[msg.sender] = totalSupply; //Give all the tokens to the creator

}

//这个方法和上面的mapping(address=>uint256) public balanceOf是等价的,当定义了balanceOf之后编译器会默认生成balanceOf这个方法

function balanceOf(address _owner) public view returns (uint256 balance)

{

return balanceOf[_owner];

}



function transfer(address _to,uint256 _value) public returns(bool success)

{

require(_to != address(0));

require(balanceOf[msg.sender] >= _value);

//防止溢出:比如之前的余额加上收到的交易代币,可能超出该数字类型所能表达的最大值,溢出之后余额反而会比之前的余额少;

require(balanceOf[_to] + _value >= balanceOf[_to]);



balanceOf[msg.sender] -= _value;

balanceOf[_to] += _value;

//触发(调用)Transfer事件

emit Transfer(msg.sender,_to,_value);



success = true;



}

function transferFrom(address _from,address _to,uint256 _value) public returns(bool success)

{

require(_to != address(0));

require(balanceOf[_from] >= _value);

require(allowed[_from][msg.sender] >= _value);

//check for overflow

require(balanceOf[_to] + _value >= balanceOf[_to]);





balanceOf[_from] -= _value;

balanceOf[_to] += _value;



emit Transfer(_from,_to,_value);



success = true;

}



function approve(address _spender,uint256 _value) public returns(bool success)

{

//_spender这个地址的账户可以从当前账户操控的金额

allowed[msg.sender][_spender] = _value;

//触发委托(Approval)事件

emit Approval(msg.sender,_spender,_value);



success = true;

}



function allowance(address _owner,address _spender) public view returns(uint256 remaining)

{

return allowed[_owner][_spender];

}

}

参考ERC-20 Token Standard

5、使用truffle创建项目

(1)安装truffle

前提:先安装好了Node.js

npm install -g truffle

(2)为Truffle工程创建文件夹并打开

先进入你要存放Truffle工程的路径

mkdir pet-shop //创建文件夹

cd pet-shop //打开文件夹

(3)创建一个新的工程

truffle init

工程创建成功之后,工程目录的结构如下所示:

  • contracts/: 智能合约的存放目录

  • migrations/: 脚本化的部署文件的存放目录

  • test/: 测试App和智能合约的目录

  • truffle.js: Truffle配置文件

若要下载一些tuffle的模板工程,可使用如下命令:

truffle unbox 

# 换成truffle模板工程名

6、部署合约

(1)安装Ganache

注意从官网上下载的Windows版的Ganache的后缀是“.appx”,是不能直接安装的,可以通过将其后缀修改为“.zip”,然后在解压文件夹,在app文件夹中直接找到“Ganache.exe”文件,直接打开即可。(Win10系统下安装Ganache)

(2)编写部署合约的脚本

参考Migration files创建一个部署合约的脚本

注意:部署合约的脚本放在”..\migrations\”文件夹下

如文件..\migrations\2_deploy_contracts.js

var Adoption = artifacts.require("Adoption"); //注意:“Adoption”表示合约的名字



module.exports = function(deployer) {

// deployment steps

deployer.deploy(Adoption);

};

部署合约的脚本写好之后,因为合约需要运行在区块链上,所以我们需要为合约准备一个区块链的环境,这时候我们就需要用到Ganache。

(3)配置truffle所需连接的网络

参考Location在truffle.js文件中配置truffle所需连接的网络

module.exports = {

// See 

// to customize your Truffle configuration!

networks: {

development: {

host: "127.0.0.1",

port: 7545, //如果连接Ganache的话,端口号就是7545

network_id: "*" // Match any network id

}

}

};

(4)编写合约测试用例

例如:下面是一个简单的宠物领养合约的测试用例(…\test\TestAdoption.sol)

pragma solidity ^0.4.20;



import "truffle/Assert.sol";

import "truffle/DeployedAddresses.sol";

import "../contracts/Adoption.sol";



contract testAdoption{



Adoption adoption = Adoption(DeployedAddresses.Adoption());

//测试用户是否可以领养该宠物(检测返回的宠物的id是否和我们期望的id是否一致)

function testUserCanAdopt( ) public{

uint returnId = adoption.adopt(8);

uint expected = 8;

Assert.equal(returnId,expected,"Adoption of petId 8 should be record.");

}

//测试合约的地址是否是该宠物领养者的地址

function testGetAdoptersAddressByPetId() public {

address adopterAddress = adoption.adopters(8);

address expected = this; //当前地址

Assert.equal(adopterAddress,expected,"Owner of petId 8 should be record. ");



}

//测试数组里面的该宠物的领养地址是否和合约中的地址匹配

function testGetAdoptersAddressByPetIdInArray() public{

address[16] memory adoptersAddresses = adoption.getAdopters();

address expected = this;

Assert.equal(adoptersAddresses[8],expected,"Owner of petId 8 should be in array");

}

}

在工程目录下运行下列命令运行测试用例:

truffle test

参考WRITING TESTS IN SOLIDITY

(5) 初始化web环境

  • (1)将当前工程转化为一个可以使用npm来管理的工程

npm init

然后填写相应信息(如package name、version、description等),之后会自动生成一个package.json文件

  • (2)安装lite-server服务器

npm install lite-server
  • (3)在工程目录下创建一个Src文件目录,并将index.html放入其中;

  • (4)为lite-server配置站点目录

在工程目录下创建一个bs-config.json文件以告诉server在哪查找文件,并配置如下:

{

"server": {

"baseDir":["./Src/","./build/contracts/"]

}

}
  • (5)在package.json文件中配置一个“dev”属性,使运行”npm run dev”命令时,运行lite-server服务器。配置部分如下

"scripts": {

"dev":"lite-server",

"test": "echo \"Error: no test specified\" && exit 1"

},
  • (6)启动web服务器,运行web工程

npm run dev

错误

(1)错误一

Ethereum笔记(一)_第1张图片

(2)错误二

在MetaMask中确认交易时出现如下错误:

ALERT: [ethjs-rpc] rpc error with payload {“id”:6832843685104,”jsonrpc”:”2.0”,”params”:[“0xf8881285174876e80082f6e7940422a0813dc48f53d9c2b845224bf0ecccb51c8280a48588b2c500000000000000000000000000000000000000000000000000000000000000012aa02a5660fb170846987d49b012eaf76b1f1b66b8f8b2b2519f3ca0c5d05f0ba5caa007e1d90886289e2925aed9367fde707936aac5dd5fa1e84fea9b38f6a36f08b7”],”method”:”eth_sendRawTransaction”} Error: the tx doesn’t have the correct nonce. account has nonce of: 10 tx has nonce of: 18

  • 解决方法:

Ethereum笔记(一)_第2张图片

(3)错误三

出现如下错误:

ALERT: Trying to call a function on a non-contract address.

Ethereum笔记(一)_第3张图片

  • 出错原因:

    因为当前区块链是空的,所以在此之前应先创建几个区块。

  • 解决方法:

    在项目的终端下运行如下命令:

truffle test //运行测试用例的时候会创建几个区块

二、参考文件

  1. Web3.js docs

  2. truffle-contract

  3. Web3.js API

你可能感兴趣的:(区块链)