以太坊(Ethereum)是一个开源的区块链平台,它不仅支持比特币那样的数字货币交易,还支持更复杂的应用程序,这些应用程序是通过智能合约来实现。
作者丨Seek
以太坊(Ethereum)是一个开源的区块链平台,它不仅支持比特币那样的数字货币交易,还支持更复杂的应用程序,这些应用程序是通过智能合约来实现。
智能合约
智能合约(Smart Contracts)是以太坊最重要的特性之一。智能合约是一段存储在以太坊区块链上的代码,它可以自动执行协议的条款。例如,你可以创建一个智能合约来管理众筹活动,当筹款达到目标时,合约会自动将资金转给项目方。
以太币 (ETH)
以太坊的原生货币称为以太币(Ether,简称 ETH)。ETH 是用于支付以太坊网络上的交易费用和计算服务的代币。用户需要支付 ETH 来执行智能合约和转账。
以太坊虚拟机 (EVM)
以太坊虚拟机(Ethereum Virtual Machine,EVM)是以太坊的核心组件。EVM 是一个图灵完备的虚拟机,它可以执行用以太坊脚本语言(如 Solidity)编写的任意代码。EVM 使得智能合约的执行变得可能。
DApps (去中心化应用)
去中心化应用(Decentralized Applications,DApps)是基于以太坊区块链和智能合约构建的应用程序。与传统应用不同,DApps 没有中央服务器,数据和应用逻辑是分布式的,这使得它们更加透明和安全。
以太坊 2.0
以太坊 2.0 是以太坊的下一代版本,旨在提高网络的可扩展性、安全性和可持续性。以太坊 2.0 引入了股权证明(Proof of Stake, PoS)共识机制,而不是现有的工作量证明(Proof of Work, PoW)。这将大幅减少能耗并提高交易处理速度。
ERC 标准
ERC 标准是以太坊的技术规范,用于创建代币和其他合约。最著名的是 ERC-20 标准,它定义了一种通用的接口,使得代币可以在不同的 DApp 之间互操作。ERC-721 是另一种标准,用于创建非同质化代币(NFT),这些代币具有独特性和不可互换性。
以太坊1.0和以太坊2.0(ETH1.0和ETH2.0)是以太坊区块链平台的两个主要版本,它们在共识机制、性能、扩展性等方面有显著的差异。以下是对两者的详细比较:
共识机制: 工作量证明(Proof of Work, PoW):ETH1.0 使用PoW共识机制,矿工通过解决复杂的数学问题来验证交易并添加区块。这一过程能耗高,效率较低。
性能: 吞吐量:ETH1.0每秒只能处理大约15-30笔交易,存在扩展性瓶颈,尤其在网络负载高峰期,交易确认时间和手续费会显著增加。
安全性: 矿池集中化:PoW机制导致矿池的集中化问题,少数大型矿池控制了大部分算力,可能带来中心化风险。
智能合约和DApps: ETH1.0支持智能合约和去中心化应用(DApps),这些应用程序已经广泛应用于各种领域,如去中心化金融(DeFi)、游戏和供应链管理。
共识机制: 权益证明(Proof of Stake, PoS):ETH2.0 使用PoS共识机制,验证者通过质押ETH来获得验证区块的机会。PoS大幅减少能耗,提高了效率和安全性。
性能:
分片链(Sharding):ETH2.0引入了分片技术,通过将区块链分成多个并行链(分片),每个分片处理不同的交易,从而显著提高了网络的吞吐量。预计 ETH2.0 将能够处理数千甚至数万笔交易每秒。
信标链(Beacon Chain):ETH2.0的核心链,负责协调分片和验证者活动,确保整个网络的同步和共识。
安全性: 去中心化和抗攻击性:PoS 机制下,恶意攻击者需要持有大量ETH,成本高昂,使得网络更安全。此外,验证者被随机选择,进一步分散风险。
智能合约和DApps: ETH2.0保留了对智能合约和DApps的支持,同时通过更高的吞吐量和更低的费用,提升了用户体验和应用性能。
过渡过程: 合并(The Merge):ETH2.0并不是从零开始的新区块链,而是对ETH1.0的升级。合并将ETH1.0的现有链和ETH2.0的PoS链结合,实现无缝过渡。
能耗: ETH2.0通过 PoS 机制大幅减少了能源消耗,相比 PoW 机制更环保。
扩展性: 分片技术和信标链的引入显著提高了网络的扩展性和吞吐量。
去中心化: ETH2.0通过随机选择验证者和经济激励机制,增强了去中心化程度和安全性。
经济模型: ETH2.0引入了新的经济模型,通过质押和奖励机制,进一步激励网络参与者,提高网络的稳定性和安全性。
Epoch, Slot, Block 和 Block 状态
ETH2.0 按照 epocho 出块
每一个 epocho 有 32 slot
每一个 slot 可以承载 1 个块
Slot(时隙)
定义: Slot 是以太坊2.0中最基本的时间单位,每个slot都有一个指定的时间长度。在每个 slot 中,可能会有一个区块被提议并添加到链中。
时间长度: 一个 slot 的长度为 12 秒。这意味着每 12 秒会有一个新的 slot。
功能: 在每个 slot 中,网络中的验证者将有机会提议一个新的区块。这些提议者是通过权益证明(PoS)随机选择的。
Epoch(纪元)
定义: Epoch 是由多个连续的slot组成的更长时间段。在 Eth2.0 中,Epoch 用于管理和组织验证者的活动。
组成: 一个 Epoch 由 32 个 slot 组成。
时间长度: 由于一个 slot 是12秒,一个 Epoch 的总长度是 384 秒(即6.4分钟)。
功能: Epoch 是用来实现共识机制的一部分。在每个 Epoch 结束时,网络会进行状态和共识的检查和调整,包括对验证者的奖励和惩罚。
Block(区块)
定义: Block 是包含交易和其他相关数据的记录单元。在以太坊2.0中,每个slot可能会有一个区块被提议,但不保证每个 slot 都有区块。
内容: 一个区块包含区块头、交易列表、状态根哈希、签名等数据。
创建过程: 在每个 slot 开始时,网络会随机选出一个验证者来提议区块。该验证者将创建一个包含新交易和其他必要信息的区块,并广播到网络中。
Safe(安全)
“Safe”状态指的是一个区块已经被多数验证者接受和认可,并且它很可能会成为最终的区块,但还没有达到完全最终确定的状态。
条件: 一个区块被认为是“safe”时,意味着它已经收到了足够多的验证者投票(attestations),通常超过了一个特定的阈值,但还没有达到最终确定的标准。
安全性: 在“safe”状态下,区块的存在是相对安全的,不太可能被回滚或被一个不同的区块链分支所替代。
作用: 这个状态用来提高网络对区块的信任度,即使在它还没有被完全最终确定之前。它帮助节点和用户判断哪些区块在短期内是可信的。
Finalized(最终确定)
“Finalized”状态指的是一个区块已经被永久地添加到区块链中,并且不可能被回滚或替代。这是区块链中最强的确认状态。
条件: 一个区块被认为是“finalized”时,必须通过了严格的共识验证,通常需要超过2/3的验证者投票同意。具体来说,两个连续的epoch被最终确定时,意味着在这两个epoch之间的所有区块都被最终确定。
安全性: 一旦区块达到“finalized”状态,它不可逆转,保证了区块链的最终一致性和数据的永久性。这种状态防止了分叉和双花攻击的可能性。
作用: 最终确定的区块为用户和应用提供了最高级别的交易安全性和网络信任度。
import { Interface } from '@ethersproject/abi';
const ethers = require('ethers');
export function createEthAddress (seedHex: string, addressIndex: string) {
const hdNode = ethers.utils.HDNode.fromSeed(Buffer.from(seedHex, 'hex'));
const {
privateKey,
publicKey,
address
} = hdNode.derivePath("m/44'/60'/0'/0/" + addressIndex + '');
return JSON.stringify({
privateKey,
publicKey,
address
});
}
import { Interface } from '@ethersproject/abi';
const ethers = require('ethers');
export async function signEthTransaction (params: any): Promise<string> {
// privateKey remove 0x
const { privateKey, nonce, from, to, gasLimit, gasPrice, amount, data, chainId, decimal, maxFeePerGas, maxPriorityFeePerGas, tokenAddress } = params;
if (!SUPPORT_CHAIN_NETWORK[chainId]) {
throw new Error(`chain id ${chainId} is not support.`);
}
const wallet = new ethers.Wallet(Buffer.from(privateKey, 'hex'));
const txData: any = {
nonce: ethers.utils.hexlify(nonce),
from,
to,
gasLimit: ethers.utils.hexlify(gasLimit),
value: ethers.utils.hexlify(ethers.utils.parseUnits(amount, decimal)),
chainId
};
if (maxFeePerGas && maxPriorityFeePerGas) {
txData.maxFeePerGas = ethers.utils.hexlify(maxFeePerGas);
txData.maxPriorityFeePerGas = ethers.utils.hexlify(maxPriorityFeePerGas);
} else {
txData.gasPrice = ethers.utils.hexlify(gasPrice);
}
if (tokenAddress && tokenAddress !== '0x00') {
const ABI = [
'function transfer(address to, uint amount)'
];
const iface = new Interface(ABI);
const idata = iface.encodeFunctionData('transfer', [to, ethers.utils.hexlify(ethers.utils.parseUnits(amount, decimal))]);
txData.data = idata;
txData.to = tokenAddress;
txData.value = 0;
}
if (data) {
txData.data = data;
}
return wallet.signTransaction(txData);
}
检查网络的 RPC 接口是否可以
curl --location 'https://eth-mainnet.g.alchemy.com/v2/apikey' \
--header 'Content-Type: application/json' \
--header 'Cookie: _cfuvid=wq9cOWHZrQJC_tuTXZLmlWkdI8GPYot1N2.FsyNsrbw-1716723624624-0.0.1.1-604800000' \
--data '{
"jsonrpc":"2.0",
"method":"eth_syncing",
"params":[],
"id":83
}'
{
"jsonrpc":"2.0",
"method":"eth_syncing",
"params":[],
"id":83
}
接口名称:eth_blockNumber
请求参数
inalized:返回已经确定的块
safe: 返回安全的块
atest: 反回最新块
请求示范
curl --location 'https://eth-mainnet.g.alchemy.com/v2/apikey' \
--header 'Content-Type: application/json' \
--header 'Cookie: _cfuvid=QpUyBoSG8Z6d1dPvSh9FzShwNUPhqBFROzt3E21ifJ8-1716722269706-0.0.1.1-604800000' \
--data '{
"jsonrpc":"2.0",
"method":"eth_blockNumber",
"params":[],
"id":83
}'
{
"jsonrpc": "2.0",
"id": 83,
"result": "0x1307827"
}
返回参数介绍
result 为最新块高
接口名称:eth_getBlockByNumber
请求参数
区块高度:获取这个区块的信息
false: 只返回交易 Hash, 不反回交易体; true 两者都返回,实际工作中用 false
请求示范
curl --location 'https://eth-mainnet.g.alchemy.com/v2/apikey' \
--header 'Content-Type: application/json' \
--header 'Cookie: _cfuvid=3WihsnbMQKfnPNI_MRn.yNT0vF2D9P4fpWlJJDPRHwU-1716723434462-0.0.1.1-604800000' \
--data '{
"jsonrpc":"2.0",
"method":"eth_getBlockByNumber",
"params":["0x130787a", true],
"id":83
}'
{
"jsonrpc": "2.0",
"id": 83,
"result": {
"baseFeePerGas": "0x1162efad6",
"blobGasUsed": "0x0",
"difficulty": "0x0",
"excessBlobGas": "0x60000",
"extraData": "0x546974616e2028746974616e6275696c6465722e78797a29",
"gasLimit": "0x1c9c380",
"gasUsed": "0xc4bd4d",
"hash": "0xf71d56324ad0dc74b92d725bb6ba5f925c1949e6c41dc2ab878d255ce7325e71",
"logsBloom": "0x33276686a78815855860127cdeb7314cb4ac424104e99422e7ed26d23833d900944425b1042a30609a21f3701b82b1581e6dcd29aa807d649b57a45a03baa1000c34c42832498e297803e32e97c1aa6e60ad9b21a66c3c5522b85f08be250644892983c247e28a7a3648c09080898cefa870b66a8a0e0c069600c9dcd02e104464d007509aa2d485406dfc2205e8670634c38c250386a22ae528007340b34c0166c61ea085a2ac138ae050d42dac8c8804c77c41c6bd4d210ce5068718105170091254721326354462e8ce284ca7d49522680286870a48d6a523950a4a34a2a511fa28d8490548884a5442838530083b84ccf0a88b1cc6c8454e8e521bc5b4e6",
"miner": "0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97",
"mixHash": "0x8bb6fdb6c7c538af8facf581292e47c9b261eab06899249d8bb205951e5026f3",
"nonce": "0x0000000000000000",
"number": "0x130788c",
"parentBeaconBlockRoot": "0xe6396e8629df3d2ceae9c3572ddefd65743b58a7d6e966a5f3e6fc28a73e1aa6",
"parentHash": "0x70b47b54a692e7144d8d832e24133127ec95829df7ad4bb5044cff64d1451af0",
"receiptsRoot": "0x2599b7a59d581c5170f83b6e015073cac8195ccb057cc79b22f75e56de9648b5",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"size": "0xdd4d",
"stateRoot": "0x2e18e4f0be435ae7fd1e97d9fa3de29a0c777181796c3e205d2357eeb1b6a89d",
"timestamp": "0x66531f17",
"totalDifficulty": "0xc70d815d562d3cfa955",
"transactions": [
"0x651260308176da1731f6178b12961c7cc5c1fabb50ed37701cb8acfdac86a5a0",
"0x82a39df2569ca6d6d853ccebb5a943f27914d8189e7b6a6751bcb16f10a84b01",
"0xf9b2428c6c0afa92e058dd8750a8ed9e52b662bbcb818d9312bce4933f96f371",
"0x58bdc6d97aba5f064d9636933b899ec4ad00fc846f9ea0b8da4b528b2fc94c4b",
],
"transactionsRoot": "0xc8401ead0c33bda562fed0d02cffc5c59a9e1ce0381f9ceeafc263b0c6499d78",
"uncles": [],
"withdrawals": [
{
"index": "0x2c89bab",
"validatorIndex": "0xc06d6",
"address": "0x210b3cb99fa1de0a64085fa80e18c22fe4722a1b",
"amount": "0x119a65a"
},
{
"index": "0x2c89bb9",
"validatorIndex": "0xc06e4",
"address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f",
"amount": "0x11be039"
},
{
"index": "0x2c89bba",
"validatorIndex": "0xc06e5",
"address": "0xb9d7934878b5fb9610b3fe8a5e441e8fad7e293f",
"amount": "0x11a853e"
}
],
"withdrawalsRoot": "0x6f44a6ed9d4e7001f9383d97405491e2c4dd7f191365fade1e7460c5ef2bd12d"
}
}
返回参数介绍
transactions: 每一笔交易的 Hash
接口名称:eth_getTransactionByHash
请求参数
💡💡交易 Hash
请求示范
curl --location 'https://eth-mainnet.g.alchemy.com/v2/apikey' \
--header 'Content-Type: application/json' \
--header 'Cookie: _cfuvid=wq9cOWHZrQJC_tuTXZLmlWkdI8GPYot1N2.FsyNsrbw-1716723624624-0.0.1.1-604800000' \
--data '{
"jsonrpc":"2.0",
"method":"eth_getTransactionByHash",
"params":["0x651260308176da1731f6178b12961c7cc5c1fabb50ed37701cb8acfdac86a5a0"],
"id":83
}'
{
"jsonrpc": "2.0",
"id": 83,
"result": {
"blockHash": "0xf71d56324ad0dc74b92d725bb6ba5f925c1949e6c41dc2ab878d255ce7325e71",
"blockNumber": "0x130788c",
"hash": "0x651260308176da1731f6178b12961c7cc5c1fabb50ed37701cb8acfdac86a5a0",
"yParity": "0x0",
"transactionIndex": "0x0",
"type": "0x2",
"nonce": "0x294958",
"input": "0x2b66e6d7ebb9f1a9519dc06d557e03c522d53520e76a5f0bc18f7db4aacb4e004c9edd5852cd905f086c759e8383e09bff1e68b3a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48006472fbc9fdfbc9fe7a025a2f61b4ac62f5ffd8775839ff667f808fd904ffa3eb6a6f259e6965fb1466a053725c031a89e6b81c2b000080f0c1c49891dcfdd40b6e0f960f84e6042bcb6fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2271072fed0e0fed1a87b47654c7cb81c2b94ffc8ae45c0ff06",
"r": "0x6bdc84eabf2199dd115398afd43739a4aacd4ba00a0490bb0ab98de975fd4281",
"s": "0x24d0c9cae048f55321628259dad6d9caa48a14ddc3178ce584f92faf04e184d5",
"chainId": "0x1",
"v": "0x0",
"gas": "0x107ff2",
"maxPriorityFeePerGas": "0x2",
"from": "0xae2fc483527b8ef99eb5d9b44875f005ba1fae13",
"to": "0x6b75d8af000000e20b7a7ddf000ba900b4009a80",
"maxFeePerGas": "0x1162efad6",
"value": "0x8c",
"gasPrice": "0x1162efad6"
}
}
返回参数解释
接口返回的 to 是交易所系统里面的用户地址,这笔交易为充值交易;
接口返回的 from 是交易所系统里面的用户地址,这笔交易为提现交易;
接口返回的 to 是交易所的归集地址,from 是系统的用户地址,这笔交易资金归集交易;
接口返回的 to 地址是冷钱包地址,from 地址时热钱包地址,这笔交易热转冷的交易。
接口返回的 from 地址是冷钱包地址,to 地址时热钱包地址,这笔交易冷转热的交易。
请求参数:
交易 Hash
请求示范
curl --location 'https://eth-mainnet.g.alchemy.com/v2/apikey' \
--header 'Content-Type: application/json' \
--header 'Cookie: _cfuvid=wq9cOWHZrQJC_tuTXZLmlWkdI8GPYot1N2.FsyNsrbw-1716723624624-0.0.1.1-604800000' \
--data '{
"jsonrpc":"2.0",
"method":"eth_getTransactionReceipt",
"params":["0x651260308176da1731f6178b12961c7cc5c1fabb50ed37701cb8acfdac86a5a0"],
"id":83
}'
{
"jsonrpc": "2.0",
"id": 83,
"result": {
"transactionHash": "0x651260308176da1731f6178b12961c7cc5c1fabb50ed37701cb8acfdac86a5a0",
"blockHash": "0xf71d56324ad0dc74b92d725bb6ba5f925c1949e6c41dc2ab878d255ce7325e71",
"blockNumber": "0x130788c",
"logsBloom": "0x00000000040800000000100000000000000000000000002000000000000000000000008000000020000000000000000802000400080020000000000000000000000000000000800948000008000000002000000000000000002000080000000000000000000000000000000000000000000010000000000280000090002800000000000008000000000000000000400000000000018000000000000000000000000000000000200000000000010000000000000100100001000004000000000000000402000000000000080000000000000000000000000000000000080000000000200000000000000000000000000000400000000002000400800000008000",
"gasUsed": "0xb8cc3",
"contractAddress": null,
"cumulativeGasUsed": "0xb8cc3",
"transactionIndex": "0x0",
"from": "0xae2fc483527b8ef99eb5d9b44875f005ba1fae13",
"to": "0x6b75d8af000000e20b7a7ddf000ba900b4009a80",
"type": "0x2",
"effectiveGasPrice": "0x1162efad6",
"status": "0x1"
}
}
返回参数解释
status 为 1 成功
status 为 0 失败
请求参数
钱包地址
请求示范
curl --location 'https://eth-mainnet.g.alchemy.com/v2/XZw9s8EsSyUtwDOjtVvzwL8N0T96Zxt0' \
--header 'Content-Type: application/json' \
--header 'Cookie: _cfuvid=wq9cOWHZrQJC_tuTXZLmlWkdI8GPYot1N2.FsyNsrbw-1716723624624-0.0.1.1-604800000' \
--data '{
"jsonrpc":"2.0",
"method":"eth_getTransactionCount",
"params":["0x4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97"],
"id":83
}'
{
"jsonrpc": "2.0",
"id": 83,
"result": "0x560c1"
}
请求参数: 无
请求示范
curl --location 'https://eth-mainnet.g.alchemy.com/v2/XZw9s8EsSyUtwDOjtVvzwL8N0T96Zxt0' \
--header 'Content-Type: application/json' \
--header 'Cookie: _cfuvid=A7vae8DmfdNdKLQ37u_mDw17rqRDDuKqXFrJuWD1ccA-1716725090138-0.0.1.1-604800000' \
--data '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":73}'
{
"jsonrpc": "2.0",
"id": 73,
"result": "0x147b5c33d"
}
返回值即为签名里面需要的 gasPrice
请求参数
签名的交易
请求示范
curl --location 'https://eth-mainnet.g.alchemy.com/v2/apikey' \
--header 'Content-Type: application/json' \
--header 'Cookie: _cfuvid=A7vae8DmfdNdKLQ37u_mDw17rqRDDuKqXFrJuWD1ccA-1716725090138-0.0.1.1-604800000' \
--data '{
"jsonrpc":"2.0",
"method":"eth_sendRawTransaction",
"params":["0x"],
"id":1
}'
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32000,
"message": "typed transaction too short"
}
}
调度签名机生成密钥对,签名机吐出公钥
使用公钥匙导出地址
获得最新块高;更新到数据库
从数据库中获取上次解析交易的块高做为起始块高,最新块高为截止块高,如果数据库中没有记录,说明需要从头开始扫,起始块高为 0;
解析区块里面的交易,to 地址是系统内部的用户地址,说明用户充值,更新交易到数据库中,将交易的状态设置为待确认。
所在块的交易过了确认位,将交易状态更新位充值成功并通知业务层。
解析到的充值交易需要在钱包的数据库里面维护 nonce, 当然也可以不维护,签名的时候去链上获取
获取离线签名需要的参数,给合适的手续费
构建未签名的交易消息摘要,将消息摘要递给签名机签名
构建完整的交易并进行序列化
发送交易到区块链网络
扫链获取到交易之后更新交易状态并上报业务层
将用户地址上的资金转到归集地址,签名流程类似提现
发送交易到区块链网络
扫链获取到交易之后更新交易状态
将热钱包地址上的资金转到冷钱包地址,签名流程类似提现
发送交易到区块链网络
扫链获取到交易之后更新交易状态
手动操作转账到热钱包地址
扫链获取到交易之后更新交易状态
注意 👇
交费的学员需要完整的项目实战代码可寻求 The Web3 社区索取
参考上面的代码
{
"jsonrpc":"2.0",
"method":"eth_getBalance",
"params":["0x90DcFfe48f4Aa981E04cEad0c47f8849ebC85F5C"],
"id":1
}
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x199e9adf0464d2"
}
根据地址获取交易记录
根据交易 Hash 获取交易详情
获取签名需要的 nonce
获取签名需要的 gas
以上接口请参考代码库: https://github.com/the-web3/wallet-chain-node/tree/develop/wallet/ethereum
HD 钱包和交易所钱包不同之处有以下几点:
HD 钱包私钥在本地设备,私钥用户自己控制
交易所钱包中心化服务器(CloadHSM, TEE 等),私钥项目方控制
HD 资金在用户钱包地址
交易所钱包资金在交易所热钱包或者冷钱包里面, 用户提现的时候从交易所热钱包提取
中心化钱包:实时不断扫链更新交易数据和状态
HD 钱包:根据用户的操作通过请求接口实现业务逻辑
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!