ETH 之 账户由来

ETH中的账户分为两类:外部账户和合约账户。账户类型谁能控制如何创建地址来源外部账户(EOA)拥有私钥的人生成一对密钥(私钥+公钥)address=keccak256(pubkey)[12:]合约账户由代码控制通过部署合约交易创建add

ETH中的账户分为两类:外部账户合约账户

账户类型 谁能控制 如何创建 地址来源
外部账户 (EOA) 拥有私钥的人 生成一对密钥(私钥 + 公钥) address = keccak256(pubkey)[12:]
合约账户 由代码控制 通过部署合约交易创建 address = keccak256(creator, nonce)create2

那么账户是怎么创建的呢?哪些行为会创建账户呢?

就这个问题,一步一步从头讲,尽量通俗易懂地串起来讲清楚这几个概念:从公钥私钥 → 外部账户 → 合约账户 → 交易 → 合约部署。

🔐 私钥与公钥(Private Key & Public Key)

以太坊账户的本质是由椭圆曲线加密算法(secp256k1)生成的。

✅ 步骤:

  1. 随机生成 32 字节私钥
  2. 用椭圆曲线计算出公钥
  3. 对公钥做 Keccak256 哈希,取后 20 字节,得到地址

💡 示例代码(使用 ethers.js):

import { Wallet } from "ethers";

// 生成新钱包(随机私钥)
const wallet = Wallet.createRandom();

console.log("私钥:", wallet.privateKey);
console.log("公钥:", wallet.publicKey);
console.log("地址:", wallet.address);

安装MetaMask钱包时

在安装 MetaMask 并点击“创建新钱包”时,它会:

  1. 生成一个 12 个单词的助记词(mnemonic)
  2. 助记词通过 BIP-39 / BIP-44 派生出一组私钥
  3. 默认第一个私钥派生出第一个账户(EOA)

MetaMask 的助记词可以生成无限多个账户(它们都来自同一个种子)。

🧠 总结图解

🌐 MetaMask 或代码生成:
    ↓
  助记词(Mnemonic) 或 随机数
    ↓
  私钥(Private Key)
    ↓
  公钥(Public Key)
    ↓
  地址(Address)

外部账户(EOA)

EOA 由私钥控制,具备以下特性:

  • 拥有以太币余额
  • 可以发起交易
  • 没有代码(code = 0)

在钱包(如 MetaMask)里看到的账户,就是一个 EOA。

合约账户(Contract Account)

  • 没有私钥
  • 代码是通过交易部署上去的 (部署合约)
  • 可以存储状态(storage)
  • 只能通过交易或调用触发其代码运行

合约账户的地址是由一个 EOA 或合约创建交易时计算得出的

如何计算合约账户的地址

参考文章:ETH 之合约账户

🔁 交易(Transaction)

交易有三种类型:

  1. 普通转账交易(EOA → EOA)
  2. 合约创建交易(EOA → 无地址)
  3. 合约调用交易(EOA → 合约地址)

交易内容包括:

  • nonce
  • to(接收方地址)
  • value(发送的 ETH)
  • data(调用合约时的数据)
  • gasLimit / gasPrice

💡 示例:发起一笔交易

const provider = new ethers.JsonRpcProvider("http://localhost:8545"); // 或 Infura 等
const signer = wallet.connect(provider);

const tx = await signer.sendTransaction({
  to: "0x1234...abcd",
  value: ethers.parseEther("0.01"),
});

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

🏗️ 合约部署(Contract Deployment)

部署合约本质是:

  • 构造一个交易,tonull(即新地址)
  • data 是合约的 初始化字节码(bytecode)
  • 合约地址由:keccak256(rlp(sender_address, nonce)) 得出

💡 示例:用 ethers.js 部署合约

import { ethers } from "ethers";
import { abi, bytecode } from "./MyContract.json";

const provider = new ethers.JsonRpcProvider("http://localhost:8545");
const signer = wallet.connect(provider);

const factory = new ethers.ContractFactory(abi, bytecode, signer);
const contract = await factory.deploy();

await contract.waitForDeployment();
console.log("合约部署地址:", contract.target);

🔄 串联整个流程

私钥 → 公钥 → 地址(EOA)  
↓  
EOA 发交易(包含 bytecode)→ 新地址(Contract Account)  
↓  
链上部署合约,合约账户诞生
↓  
之后可以通过交易调用合约方法

你可以把这个过程理解成:

🔑 你拥有钥匙 → 👤 创建账户 → 📦 发布代码 → 🧠 拥有合约 → 🚀 运行逻辑

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Henry Wei
Henry Wei
Web3 探索者