前面已经把基础环境打通,我们现在正式进入实战:构建第一个Web3开发入门项目 —— 留言板。初步的目标是:初始化项目、编写代码、跑通测试和部署。
一、创建入门项目的工作目录
我们把项目目录放在 /web3-guestbook, 在哪个目录下创建web3-guestbook这个目录比较好呢?
我用的是Ubuntu系统,在 Ubuntu 系统中,创建项目目录主要遵循“方便权限管理”和“符合开发者习惯”两个原则。所以推荐在用户家目录 (~) 下创建一个专门存放代码的文件夹。比如: ~/projects
这是大多数 Linux 开发者的标准做法
# 1. 回到家目录cd ~
# 2. 创建一个通用的代码仓库文件夹mkdir -p projects
# 3. 进入该文件夹cd projects
# 4. 在这里创建你的 Web3 项目mkdir web3-guestbookcd web3-guestbook
为什么不建议在其他地方创建?
- 不要在 /root 下创建:那是超级管理员的领地,频繁使用 sudo 会导致 Foundry 的权限检查出错,后续前端项目安装 npm 包时也会遇到各种棘手的权限问题。
- 不要在 /var/www 下创建:虽然这是传统 Web2 服务器(如 Apache/Nginx)存放网页的地方,但在开发阶段,你需要频繁读写文件,放在家目录下最安全且顺手。
- 不要在桌面 (~/Desktop) 下创建:虽然容易找到,但当你的项目产生数千个 node_modules 文件时,某些文件管理器的索引可能会让系统变慢。
整理后的完整路径
项目的最终路径看起来应该是:/home/你的用户名/projects/web3-guestbook
验证当前位置
可以输入 pwd 命令。如果输出是以 /home/你的用户名/… 开头的,那就OK了。
二、实现项目的后端
第一步:初始化项目
在终端中执行以下命令。这会创建一个标准化的 Foundry 项目模板:
cd web3-guestbookforge init
执行完后,你会发现多了几个文件夹。最重要的三个是:
- src/: 你的核心逻辑(Solidity 合约)就在这里。
- test/: 你的“防弹衣”,所有的自动化测试都在这里。
- lib/: 这里存放着 Foundry 的标准库 forge-std。
第二步:编写留言板合约
删除 src/ 下默认生成的 Counter.sol,新建一个文件 src/Guestbook.sol。
我们将实现三个核心点:存储结构、写入函数、读取函数。
具体的代码在前面的文章里,这里就不再展示了。
第三步:编译合约
在终端输入:
forge build
如果看到 Compiled 5 files with 0.8.x 之类的成功提示,说明你的代码逻辑没有语法错误。此时 Foundry 会在 /out 文件夹下生成 ABI 文件(这是未来前端连接合约的钥匙)。
第四步:本地测试 (Foundry 的精髓)
在 Web3 开发中,不写测试就部署等于“裸奔”。我们用 Solidity 来写测试。
尤其需要注意的是,针对“打赏”和“提款”逻辑写两个关键测试:
- 测试带钱留言:验证合约是否收到了 ETH。
- 测试权限提取:验证非 Owner 是否无法偷走钱。
和第二步类似,删除 test/Counter.t.sol,新建 test/Guestbook.t.sol:
具体的代码见前面的文章,这里不再展示。
第五步:运行测试
见证奇迹的时刻,在终端输入:
forge test
如果你看到两个绿色的 [PASS],恭喜你!你已经成功完成了 后端合约层 的开发。
第六步:本地模拟部署
启动 Foundry 自带的本地区块链 anvil,尝试用命令行工具 cast 去真实地“发一笔交易”。
启动本地私链 (Anvil)
现在,我们要跳出“测试”环境,进入“模拟真实”环境。
- 打开一个新的终端窗口。
- 输入 anvil 并回车。

- 你会看到 10 个自带 10000 ETH 的初始账户。
- 区块链现在正在 127.0.0.1:8545 运行。
用 Cast 手动发一笔交易
打开一个新的终端,尝试用命令行与这个合约交互(不需要前端也能玩):
1. 部署到本地 Anvil (假设使用 Anvil 提供的第一个私钥):
切换到后端相应的目录 ~/projects/web3-guestbook
运行下面的命令:
forge create src/Guestbook.sol:Guestbook --interactive
按提示输入 Anvil 给你的第一个私钥。
2. 留言并打赏:
# 将 <CONTRACT_ADDRESS> 替换为上面部署输出的地址cast send <CONTRACT_ADDRESS> "leaveMessage(string)" "Hello Web3!" --value 1ether --private-key <PRIVATE_KEY>
3. 查看合约余额:
cast balance <CONTRACT_ADDRESS>
三、常见的问题
1.误关 anvil 窗口
如果不小心把anvil 终端窗口关了,怎么办?
这是刚开始接触 CLI(命令行界面)开发时最常遇到的情况。在 Linux/Ubuntu 中,关闭终端窗口通常意味着:
- 如果你关掉的是运行 anvil 的窗口:本地节点进程已经停止了,刚才部署在内存里的合约也随之消失了(因为 anvil 默认是不持久化的)。
- 如果你关掉的是编写代码的窗口:别担心,代码已经存入硬盘了,只要 cd 回去即可。
解决办法:
1. 回到项目目录
打开一个新的终端,输入:cd ~/projects/web3-guestbook
2. 重启本地节点 (Anvil)
Web3 开发需要一个持续运行的区块链环境。
- 命令:再次输入 anvil。
- 注意:这个窗口必须保持开启。它就像你的服务器,关了网页(前端)就连不上了。你可以把它最小化,或者在终端里使用 Ctrl+Shift+T 开一个新标签页处理其他事。
3. 重新部署合约
因为 anvil 重启后是“干净”的,你需要重新获取一个合约地址:
# 使用 anvil 提供的第一个私钥(通常是0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80)# 建议先存成环境变量,省得每次复制粘贴export PRIV_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
# 部署forge create src/Guestbook.sol:Guestbook --private-key $PRIV_KEY
记下输出结果中的 Deployed to: 0x… 地址,接下来的操作就靠它了。
一个提高效率的小技巧:使用 tmux 或终端标签页
为了防止误关,Web3 开发者通常可以这样分配屏幕:
- 左侧/标签页 1:运行 anvil(看交易日志)。
- 右侧/标签页 2:写代码和运行 forge test。
- 底部/标签页 3:运行前端 npm run dev。
如果你想更专业一点,可以安装 tmux:sudo apt install tmux
输入 tmux 后,即便意外关闭了终端窗口,后台的进程依然会运行,可以通过 tmux attach 随时找回刚才的现场。
2. 运行 forge create 时的常见问题
运行forge create 时如果没有显示 Deployed to 地址,通常是因为 forge create 命令执行时由于某些配置问题导致交易没发出去。
比如,常见的一个情况是Warning: To broadcast this transaction, add –broadcast to the previous command. See forge create –help for more
这说明你的命令已经成功模拟了部署,但 Foundry 默认为了安全,不会直接把交易发送到链上,除非你显式加上 –broadcast 参数。这就像是你写好了支票,但还没把它递给银行柜员。
请在终端执行这个完整的命令:
forge create src/Guestbook.sol:Guestbook \--rpc-url http://127.0.0.1:8545 \--private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \--broadcast
3.部署成功后会看到什么
执行完带 --broadcast 的命令后,终端会跳出很多信息,

请睁大眼睛寻找这一行:
Transaction hash: 0x…
Deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
注意: 这里的 Deployed to就是Contract Address 就是我们要找的“留言板”地址。请把它复制并保存到记事本里,因为接下来所有的操作(打赏、留言、前端连接)都要用到它。
验证步骤(确保合约真的“活”了)
一旦你拿到了地址,可以运行下面这个命令来考考区块链:# 将 <你的合约地址> 替换成刚才输出的 0x...cast call <你的合约地址> "owner()"
如果返回的是 0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266(去掉前面的零,就是 Anvil 的第一个账户地址),说明你的合约已经正式在本地链上安家了!
比如,我拿到的Contract Address 是0x5FbDB2315678afecb367f032d93F642f64180aa3
这就是留言板合约在本地区块链上的“地址”。
现在,我们直接在终端里玩转这个合约,完成留言、打赏、查询、提款的全流程。这能让你在上前端之前,彻底搞清楚 Web3 的交互底层逻辑。
3.1 存入环境变量
为了避免后续命令又长又乱,先在终端执行这两行:export CA=0x5FbDB2315678afecb367f032d93F642f64180aa3export PK=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
3.2 发送第一条“带钱”留言
我们要调用 leaveMessage 函数,并打赏 0.1 ETH。cast send $CA "leaveMessage(string)" "Hello Web3, I am here!" --value 0.1ether --private-key $PK
指令解析:cast send 用于发送改变链上状态的交易。–value 后接打赏金额。
3.3 验证数据,读取合约状态
区块链最迷人的地方就是透明。我们来查查刚才的留言:cast call $CA "getMessages()"
你会看到一串很长的十六进制(Hex)。这是 EVM 的原始编码。
想看清晰的余额?执行这个:cast balance $CA --ether
输出应该是 0.100000000000000000,说明钱已经安全存入合约账户了。
3.4 权限挑战:尝试“提款”
既然你是这个合约的 owner,你可以把里面的 0.1 ETH 提走。cast send $CA "withdraw()" --private-key $PK
提款成功后,再次运行 cast balance $CA,余额应该归零了,而你钱包里的钱增加了。
4.区分“钱包地址”与“合约地址”
上面提到 # 将 <CONTRACT_ADDRESS> 替换为上面部署输出的地址
cast send <CONTRACT_ADDRESS> “leaveMessage(string)” “Hello Web3!” –value 1ether –private-key <PRIVATE_KEY>
这是一个需要特意关注的地方,在 Web3 开发中,区分清楚“钱包地址”和“合约地址”是特别重要的一点。
你需要替换的是 Deployed to: 0x… 后面那一串字符。
4.1 哪里找这个地址?
当你运行 forge create 成功后,终端会输出类似下面的内容:Deployer: 0xf39Fd6e51a... (这是你的钱包地址)
Deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3 <– 就是这个Deployed to!Transaction hash: 0x...
- Deployer (部署者):这是发起的账户(就像发件人)。
- Deployed to (合约地址):这是你的“留言板”在区块链上的永久居住地。以后任何人想留言,都要把请求发往这个地址。
4.2 实际操作演示 (以 Anvil 为例)
假设你的合约地址是 0x5FbDB2315678afecb367f032d93F642f64180aa3,私钥是 Anvil 默认的第一个。
你可以直接在终端通过设置环境变量来简化命令(这样不容易出错):
# 1. 设置合约地址 (换成你屏幕上实际看到的那个)export CA=0x5FbDB2315678afecb367f032d93F642f64180aa3
# 2. 设置私钥 (Anvil 的第一个私钥)export PK=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
# 3. 发送带钱的留言cast send $CA "leaveMessage(string)" "Hello Web3!" --value 0.1ether --private-key $PK
4.3 如何验证钱真的存进去了?
发送完上面的 cast send 后,你会看到一个详细的交易收据。接着你可以运行这两个命令来“查账”:
- 查合约余额(看看那 0.1 ETH 到了吗):
cast balance $CA
输出应该是 100000000000000000,单位是 Wei,即 0.1 ETH - 查留言内容(读取合约状态):
cast call $CA "getMessages()"
它会返回一串编码后的十六进制数据,这就是区块链的原始数据
注意:
如果你刚才关了窗口没记下地址,别担心。只要 Anvil 窗口没关,你可以往上翻一翻日志;如果 Anvil 也关了,那就必须重新运行 forge create 部署一遍,因为每次重启 Anvil 都是一个全新的平行宇宙,旧的合约地址就失效了。
