Solidity 智能开发知识点记录

Solidity 智能开发知识点记录

    • [1. 特性](#1. 特性)
    • [2. ==存储区域==](#2. ==存储区域==)
    • [3. 事件(Event)](#3. 事件(Event))
  • ABI

1. 特性

Solidity 的核心特性包括:

  • 面向合约 :以 contract 为基本单位,合约类似面向对象语言中的类,包含状态变量、函数、事件等。
  • 静态类型:变量类型在编译时确定,且不可动态改变。
  • 继承与多态 :支持多重继承,使用 is 关键字,并允许子合约重写父合约函数。
  • EVM 原生兼容:编译后生成以太坊虚拟机字节码,可直接部署在以太坊及兼容链上。
  • 错误处理 :提供 requireassertrevert 等断言式错误抛出机制。
  • 内置区块链信息 :可访问 block.numbermsg.sendertx.gasprice 等环境变量。
  • Gas 感知 :通过 viewpure 等修饰符标明函数消耗 Gas 的情况。

2. 存储区域

Solidity 中的数据有明确的存储位置,主要分为四类:

区域 关键字 生命周期 适用场景 特点
Storage storage 永久(合约状态) 状态变量(默认) 写入需消耗 Gas,数据存储在链上
Memory memory 临时(函数调用) 函数内临时变量、函数参数(某些类型)、动态数组拷贝 读写成本低于 Storage,调用结束释放
Calldata calldata 临时(仅外部调用) 外部函数的参数(不可修改) 只读,不占用 Memory 拷贝,节省 Gas
Stack 无关键字 短暂(表达式内) 局部基本类型(如 uintbool),存放指令操作数 深度限制 1024 个元素

重要规则

  • 状态变量(合约内声明的变量)默认storage
  • 函数局部变量的存储位置需要显式指定(结构体、数组、映射等复杂类型)。
  • 赋值时注意引用传递:storage 赋值给 storage 会传递引用;memory 赋值给 storage 会拷贝。
solidity 复制代码
contract Example {
    uint[] public arr; // storage

    function test(uint[] calldata source) external {
        uint[] memory tmp = new uint[](10); // memory
        arr = tmp;      // 从 memory 拷贝到 storage
        arr = source;   // 从 calldata 拷贝到 storage
    }
}

常见数据类型:uintintbooladdressbytesstringmapping、数组、结构体、enum


3. 事件(Event)

事件是 Solidity 中日志 的抽象,用于和链外应用通信。

核心作用

  • 智能合约返回数据给前端/后端监听者。
  • 比普通返回值更 Gas 高效(日志存储在交易收据中,合约无法访问)。
  • 可以带索引参数(indexed),方便链外按条件快速检索。

语法

solidity 复制代码
event EventName(
    type indexed param1,
    type param2
);
  • 事件日志由两部分组成:主题(topics)和数据(data)
    • 第一个参数:事件签名的哈希值。
    • 第二个参数:自定义 indexed 参数
    • 第三个参数:自定义 indexed 参数
    • 第四个参数:自定义 indexed 参数
  • indexed 参数最多 3 个,会被日志的 topic 区域存储,可用于过滤。
  • 非索引参数(data 区域)原样存储,无法直接检索
  • 合约执行每触发一次事件,在交易回执里的 logs 数据项数组里就会多一条日志条目
java 复制代码
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "blockHash": "0x6a0e591eb3c266bd1d499f17caea929dc3a1b396b6e08d3d12b1df7abb4b1daf",
        "blockNumber": "0x12d11ab",
        "contractAddress": null,
        "cumulativeGasUsed": "0x679b6b",
        "effectiveGasPrice": "0x1ff2895dc",
        "from": "0xe4de99fbf078eff6ba02b076e503b304c2a7b1c5",
        "gasUsed": "0xe074",
        "logs": [
            {
                "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
                "topics": [
                    "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
                    "0x000000000000000000000000e4de99fbf078eff6ba02b076e503b304c2a7b1c5",
                    "0x0000000000000000000000006177d42837d88b1f6dd0ad14e2f80c17df3d0617"
                ],
                "data": "0x000000000000000000000000000000000000000000000000000000000ee6b280",
                "blockNumber": "0x12d11ab",
                "transactionHash": "0xe26a8add9f159c22d8d10f4b4069ed20ec9245ba07bf742dc2054d6b2561654a",
                "transactionIndex": "0x4b",
                "blockHash": "0x6a0e591eb3c266bd1d499f17caea929dc3a1b396b6e08d3d12b1df7abb4b1daf",
                "logIndex": "0xb2",
                "removed": false
            }
        ],
        "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000800000000000000000008000008000400000000010000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000100000000000000000000000010000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000002000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        "status": "0x1",
        "to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
        "transactionHash": "0xe26a8add9f159c22d8d10f4b4069ed20ec9245ba07bf742dc2054d6b2561654a",
        "transactionIndex": "0x4b",
        "type": "0x2"
    }
}

触发事件

solidity 复制代码
emit EventName(param1, param2);

链外监听示例(JavaScript + ethers.js)

javascript 复制代码
contract.on("EventName", (param1, param2, event) => {
    console.log(param1, param2);
});

典型应用场景:代币转账 Transfer 事件、去中心化交易所订单状态变更、治理投票记录等。

ABI

ABI(Application Binary Interface,应用二进制接口)是智能合约与外部世界(前端、其他合约、钱包等)交互的标准化规范。

智能合约在以太坊上以字节码形式存在,人类无法直接理解。ABI 就像是"说明书",告诉外部程序:

  1. 合约有哪些函数
  2. 函数参数和返回值是什么类型
  3. 如何编码调用数据
  4. 如何解码返回结果
solidity 复制代码
// ContractABI.json
[
  {
    "inputs": [{ "internalType": "uint256", "name": "x", "type": "uint256" }],
    "name": "set",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "get",
    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "anonymous": false,
    "inputs": [
      { "indexed": true, "internalType": "address", "name": "caller", "type": "address" },
      { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" }
    ],
    "name": "ValueSet",
    "type": "event"
  }
]

如何调用?

java 复制代码
package com.example;

import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.FunctionReturnDecoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.EthCall;
import org.web3j.protocol.core.methods.response.EthGetLogs;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.core.methods.response.Log;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.RawTransactionManager;
import org.web3j.tx.gas.DefaultGasProvider;
import org.web3j.tx.gas.StaticGasProvider;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class CallContractWithABI {
    
    private static final String RPC_URL = "https://sepolia.infura.io/v3/YOUR_KEY";
    private static final String CONTRACT_ADDRESS = "0x1234567890abcdef...";
    private static final String PRIVATE_KEY = "YOUR_PRIVATE_KEY";
    
    public static void main(String[] args) throws Exception {
        Web3j web3j = Web3j.build(new HttpService(RPC_URL));
        Credentials credentials = Credentials.create(PRIVATE_KEY);
        
        // 调用只读方法
        callReadMethod(web3j);
        
        // 调用写入方法
        callWriteMethod(web3j, credentials);
        
        // 查询历史事件
        queryEvents(web3j);
        
        // 实时监听事件
        listenEvents(web3j);
        
        web3j.shutdown();
    }
    
    /**
     * 调用只读方法(view/pure)- 不消耗 Gas
     */
    private static void callReadMethod(Web3j web3j) throws Exception {
        System.out.println("=== 调用 get() 方法 ===");
        
        // 1. 创建 Function 对象
        Function function = new Function(
            "get",                           // 函数名
            Collections.emptyList(),         // 参数列表(无参数)
            Arrays.asList(new TypeReference<Uint256>() {})  // 返回值类型
        );
        
        // 2. 编码调用数据
        String encodedFunction = FunctionEncoder.encode(function);
        
        // 3. 创建交易请求
        Transaction transaction = Transaction.createEthCallTransaction(
            null,                    // from(只读可以为 null)
            CONTRACT_ADDRESS,        // to
            encodedFunction          // data
        );
        
        // 4. 执行调用
        EthCall response = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
        
        // 5. 解码返回值
        if (response.isReverted()) {
            System.out.println("调用失败: " + response.getRevertReason());
            return;
        }
        
        String rawOutput = response.getResult();
        List<Type> decoded = FunctionReturnDecoder.decode(rawOutput, function.getOutputParameters());
        
        if (!decoded.isEmpty()) {
            BigInteger value = (BigInteger) decoded.get(0).getValue();
            System.out.println("当前存储值: " + value);
        }
    }
相关推荐
StockTV5 小时前
新加坡股票API 实时行情、K 线及指数数据
android·java·spring boot·后端·区块链
ZFJ_张福杰5 小时前
【区块链】我实现了 UTXO 自动选择算法(最小手续费策略)
区块链·交易·utxo·手续费
搬砖的小码农_Sky5 小时前
比特币区块链的算法架构
算法·架构·去中心化·区块链
小王毕业啦21 小时前
(1990-2024年)个股交易活跃度、个股换手率
大数据·人工智能·数据挖掘·数据分析·区块链·社科数据
app软件定制开发173770910721 天前
世界杯应用开发的关键要点与注意事项
大数据·区块链
OneBlock Community1 天前
经济模型大升级 + 首只 DOT ETF 落地,Polkadot 的新周期来了?
区块链
区块链小八歌1 天前
链上资本的“工业革命”:拆解 Berachain “Bera Builds Businesses” 的真实业务版图
区块链
狙击主力投资工具2 天前
26年5月4日本周复盘总结,好票机会,下周大盘方向,热门板块方向,操作建议,实用干货
人工智能·区块链
长安链开源社区3 天前
长安链开发大赛 在期待什么样的作品?
web3·区块链