以太坊开发基础

以太坊开发基础

以太坊是最大的智能合约平台,为去中心化应用提供了强大的基础设施。本章将介绍以太坊的核心概念和开发基础。

以太坊架构

以太坊是一个去中心化的计算平台,其核心组件包括:

1. 账户系统

以太坊有两种类型的账户:

  1. 外部账户(EOA)
  2. 由私钥控制
  3. 可以发起交易
  4. 没有相关代码

  5. 合约账户

  6. 由代码控制
  7. 只能响应交易
  8. 包含智能合约代码
1
2
3
4
5
6
7
8
9
// 创建钱包
const wallet = ethers.Wallet.createRandom();
console.log('地址:', wallet.address);
console.log('私钥:', wallet.privateKey);
console.log('助记词:', wallet.mnemonic.phrase);

// 导入私钥
const privateKey = '0x...';
const importedWallet = new ethers.Wallet(privateKey);

2. 交易模型

以太坊交易包含以下字段:

1
2
3
4
5
6
7
8
9
const transaction = {
    nonce: 0,              // 交易序号
    gasPrice: 20000000000, // Gas价格(wei)
    gasLimit: 21000,       // Gas限制
    to: '0x...',          // 接收地址
    value: 1000000000,    // 转账金额(wei)
    data: '0x...',        // 调用数据
    chainId: 1            // 网络ID
};

3. 状态转换

1
2
3
+----------------+      +----------------+      +----------------+
|   状态 S(n)    |  ->  |     交易Tx     |  ->  |   状态 S(n+1)  |
+----------------+      +----------------+      +----------------+

Gas机制

Gas是以太坊的计算资源度量单位:

1. Gas计算

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 估算Gas费用
async function estimateGas(transaction) {
    const provider = new ethers.providers.JsonRpcProvider();
    const gasEstimate = await provider.estimateGas(transaction);

    // 获取当前Gas价格
    const gasPrice = await provider.getGasPrice();

    // 计算总费用
    const totalCost = gasEstimate.mul(gasPrice);
    return ethers.utils.formatEther(totalCost);
}

2. Gas优化技巧

  1. 存储优化
1
2
3
4
5
// 不好的做法
uint256[] public numbers;

// 好的做法
uint256[10] public numbers;
  1. 循环优化
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 不好的做法
for(uint i = 0; i < array.length; i++) {
    // 操作
}

// 好的做法
uint length = array.length;
for(uint i = 0; i < length; i++) {
    // 操作
}

以太坊虚拟机(EVM)

EVM是以太坊的核心计算引擎:

1. 指令集

EVM操作码示例:

1
2
3
4
5
6
PUSH1 0x60     // 压入值0x60
PUSH1 0x40     // 压入值0x40
MSTORE         // 存储操作
PUSH1 0x20     // 压入值0x20
PUSH1 0x00     // 压入值0x00
RETURN         // 返回操作

2. 内存模型

EVM的内存分为三个区域:

  1. Stack
  2. 最大1024个元素
  3. 每个元素256位
  4. PUSH/POP操作

  5. Memory

  6. 线性寻址
  7. 按字节访问
  8. 临时存储

  9. Storage

  10. 持久存储
  11. 键值对结构
  12. 高Gas成本

网络类型

以太坊有多个网络环境:

1. 主网(Mainnet)

1
2
3
4
// 连接主网
const mainnet = new ethers.providers.JsonRpcProvider(
    "https://mainnet.infura.io/v3/YOUR-PROJECT-ID"
);

2. 测试网

1
2
3
4
5
6
7
8
9
// 连接Goerli测试网
const goerli = new ethers.providers.JsonRpcProvider(
    "https://goerli.infura.io/v3/YOUR-PROJECT-ID"
);

// 连接Sepolia测试网
const sepolia = new ethers.providers.JsonRpcProvider(
    "https://sepolia.infura.io/v3/YOUR-PROJECT-ID"
);

3. 本地网络

1
2
3
4
// 连接本地网络
const localhost = new ethers.providers.JsonRpcProvider(
    "http://localhost:8545"
);

交易处理

1. 发送交易

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
async function sendTransaction(to, value) {
    const wallet = new ethers.Wallet(privateKey, provider);

    const tx = await wallet.sendTransaction({
        to: to,
        value: ethers.utils.parseEther(value)
    });

    console.log('交易哈希:', tx.hash);

    // 等待交易确认
    const receipt = await tx.wait();
    console.log('交易确认:', receipt);
}

2. 监听交易

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 监听新区块
provider.on('block', (blockNumber) => {
    console.log('新区块:', blockNumber);
});

// 监听特定地址的交易
const address = '0x...';
provider.on(address, (tx) => {
    console.log('新交易:', tx);
});

数据类型和单位

1. 常用数据类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 基本类型
uint256 number = 42;
address wallet = 0x123...;
bool flag = true;
string text = "Hello";
bytes32 hash = 0x456...;

// 数组
uint[] numbers = [1, 2, 3];
string[] texts = ["a", "b", "c"];

// 映射
mapping(address => uint) balances;

2. 单位转换

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Wei转换
const oneEther = ethers.utils.parseEther("1.0");
console.log('1 ETH in Wei:', oneEther.toString());

// 格式化Wei为ETH
const wei = "1000000000000000000";
console.log('Wei to ETH:', ethers.utils.formatEther(wei));

// Gas单位
const gwei = ethers.utils.parseUnits("1.0", "gwei");
console.log('1 Gwei in Wei:', gwei.toString());

实用工具

1. 地址验证

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 检查地址格式
function isValidAddress(address) {
    return ethers.utils.isAddress(address);
}

// 计算合约地址
function getContractAddress(from, nonce) {
    return ethers.utils.getContractAddress({
        from: from,
        nonce: nonce
    });
}

2. 数据编码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// ABI编码
const abiCoder = new ethers.utils.AbiCoder();

// 编码函数调用
const encoded = abiCoder.encode(
    ['string', 'uint256'],
    ['Hello', 123]
);

// 解码数据
const decoded = abiCoder.decode(
    ['string', 'uint256'],
    encoded
);

开发工具

1. 开发环境

  • Hardhat
  • Truffle
  • Remix
  • Ganache

2. 测试框架

  • Mocha
  • Chai
  • Waffle
  • Ethers.js

3. 开发库

  • Web3.js
  • Ethers.js
  • OpenZeppelin

练习题

  1. 解释以太坊账户系统的两种类型及其区别。

  2. 实现一个函数来检查交易状态:

1
2
3
4
// 练习:实现交易状态检查
async function checkTransaction(txHash) {
    // 你的代码
}
  1. 编写一个Gas估算函数:
1
2
3
4
// 练习:实现Gas估算
async function calculateGas(tx) {
    // 你的代码
}
  1. 描述EVM的三种内存区域及其特点。

  2. 实现一个简单的代币转账函数:

1
2
3
4
// 练习:实现代币转账
async function transferToken(tokenAddress, to, amount) {
    // 你的代码
}

参考资源

  1. 以太坊黄皮书
  2. EVM深入解析
  3. Gas和费用
  4. 以太坊开发工具
  5. Ethers.js文档