Solidity 智能开发知识点记录

Solidity 智能开发知识点记录

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

1. 特性

Solidity 的核心特性包括:

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

2. 存储区域

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

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

常见数据类型:uint、int、bool、address、bytes、string、mapping、数组、结构体、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);
        }
    }
相关推荐
旋生万物1 天前
全息编码:从 CRC 到 Merkle Tree 到区块链的统一视角
区块链·#人工智能·#后端开发·#软件工程·#数据结构与算法·#云原生·#分布式系统
ZDGJ60991 天前
国际期货交易中如何选择交易时机?
区块链
MuMuMu12233 天前
越华环保集团碳惠小屋:物联网 + 区块链,构建碳普惠终端数据可信与隐私保护体系
物联网·区块链
IvorySQL3 天前
PostgreSQL 日报| PgBouncer 修复三个 CVE 漏洞(10 月 15 日)
数据库·postgresql·区块链
十二同学啊3 天前
反洗钱体系详解:KYC、风险评级、交易监控与可疑交易报告
web3·区块链·智能合约
海宇大数据3 天前
零信任架构实战:基于海宇公安二要素认证即时版构建自动化证券账户实名鉴权网关
人工智能·架构·自动化·区块链
磐链科技4 天前
DApp技术架构全面解析:从区块链底层、前后端开发到链上数据交互体系设计
架构·区块链
ZDGJ60994 天前
国际期货交易时段流动性影响因素
区块链
IvorySQL5 天前
PostgreSQL 日报| pg_vectorsearch 开源向量搜索发布(10 月 14 日)
数据库·人工智能·postgresql·开源·区块链