当前位置: 首页 > web >正文

Solidity合约编程基础知识

目录

    • 合约结构(contract)
    • 交易属性
    • msg全局变量
    • 数值
    • 字符串 & require校验
    • mapping结构
    • 数组
    • 阅读投票合约

合约结构(contract)

https://docs.soliditylang.org/zh-cn/latest/structure-of-a-contract.html#

交易属性

区块和交易属性
block.blockhash(uint blockNumber) returns (bytes32):指定区块的区块哈希——仅可用于最新的 256 个区块且不包括当前区块;而 blocks 从 0.4.22 版本开始已经不推荐使用,由 blockhash(uint blockNumber) 代替
block.coinbase (address): 挖出当前区块的矿工地址
block.difficulty (uint): 当前区块难度
block.gaslimit (uint): 当前区块 gas 限额
block.number (uint): 当前区块号
block.timestamp (uint): 自 unix epoch 起始当前区块以秒计的时间戳
gasleft() returns (uint256):剩余的 gas
msg.data (bytes): 完整的 calldata
msg.gas (uint): 剩余 gas - 自 0.4.21 版本开始已经不推荐使用,由 gesleft() 代替
msg.sender (address): 消息发送者(当前调用)
msg.sig (bytes4): calldata 的前 4 字节(也就是函数标识符)
msg.value (uint): 随消息发送的 wei 的数量
now (uint): 目前区块时间戳(block.timestamp)
tx.gasprice (uint): 交易的 gas 价格
tx.origin (address): 交易发起者(完全的调用链)

msg全局变量

在 Solidity 中,msg 是一个 全局对象(全局变量),它包含了与当前 外部函数调用(transaction 或 call) 相关的关键信息。它是智能合约与外部世界(如用户、钱包、其他合约)交互时最重要的数据来源之一。

属性类型说明
msg.senderaddress调用者地址(当前函数的直接调用者)
msg.valueuint随交易发送的 以太币数量(单位:wei)
msg.databytes calldata完整的调用数据(包括函数签名和参数)
msg.sigbytes4函数签名的哈希(前 4 字节)
msg.gasuint剩余的 gas(⚠️ Solidity 0.8.0+ 已废弃)

数值

类型位数最大值表达式
uint882552**8 - 1
uint161665,5352**16 - 1
uint32324,294,967,2952**32 - 1
uint646418,446,744,073,709,551,6152**64 - 1
uint2562562**256 - 1(极大)Solidity 默认整数类型

例如不符合数值范围的输入,remix部署报错如下:
在这里插入图片描述

字符串 & require校验

/*** 拼接两个字符串,要求总长度 ≤ 16,否则 revert*/function concatRequireLimit(string memory str1, string memory str2)publicpurereturns (string memory){bytes memory b1 = bytes(str1);bytes memory b2 = bytes(str2);require(b1.length + b2.length <= 16, "Total length exceeds 16");bytes memory result = new bytes(b1.length + b2.length);uint256 k = 0;for (uint256 i = 0; i < b1.length; i++) {result[k++] = b1[i];}for (uint256 i = 0; i < b2.length; i++) {result[k++] = b2[i];}return string(result);}
  • 正常例子
    在这里插入图片描述
  • 异常例子
    在这里插入图片描述

mapping结构

  1. 它无法迭代keys,因为它只保存键的哈希,而不保存键值,如果想迭代,可以用开源的可迭代哈希类库

  2. 如果一个key未被保存在mapping中,一样可以正常读取到对应value,只是value是空值(字节全为0)。所以它也不需要put、get等操作,用户直接去操作它即可。

eg1: 简单映射:地址 → 余额

pragma solidity ^0.8.0;contract SimpleMapping {// 每个地址对应一个余额(单位:wei)mapping(address => uint256) public balances;function setBalance(address _addr, uint256 _amount) public {balances[_addr] = _amount;}// public 会自动生成 getter 函数// 调用 balances[0x...] 可查询
}

eg2: 映射 + 结构体:用户信息管理

struct User {string name;uint256 age;bool active;
}// 用户地址 → 用户信息
mapping(address => User) public users;function setUser(string memory _name, uint256 _age) public {users[msg.sender] = User({name: _name,age: _age,active: true});
}

eg3: 映射 + 数组:一对多关系

// 每个用户可以有多个订单 ID
mapping(address => uint256[]) public userOrders;function addOrder(uint256 orderId) public {userOrders[msg.sender].push(orderId);
}

数组

contract Sample{
​string[] private arr;
​function arraySample() public view {arr.push("Hello");uint len = arr.length;//should be 1string value = arr[0];//should be Hello}}

局部变量数组

function arraySample() public view returns(uint){//create an empty array of length 2uint[] memory p = new uint[](2);p[3] = 1;//THIS WILL THROW EXCEPTION return p.length;
}
Copy to clipboard

阅读投票合约

https://docs.soliditylang.org/zh-cn/latest/solidity-by-example.html#voting

  • 初始化,提案投票都是0
    /// 为 `proposalNames` 中的每个提案,创建一个新的(投票)表决constructor(bytes32[] memory proposalNames) {chairperson = msg.sender;voters[chairperson].weight = 1;// 对于提供的每个提案名称,// 创建一个新的 Proposal 对象并把它添加到数组的末尾。for (uint i = 0; i < proposalNames.length; i++) {// `Proposal({...})` 创建一个临时 Proposal 对象// `proposals.push(...)` 将其添加到 `proposals` 的末尾proposals.push(Proposal({name: proposalNames[i],voteCount: 0}));}}
  • 投票: 提案投票数加上调用者即投票人的权重
 /// 把您的票(包括委托给您的票),/// 投给提案 `proposals[proposal].name`。function vote(uint proposal) external {Voter storage sender = voters[msg.sender];require(sender.weight != 0, "Has no right to vote");require(!sender.voted, "Already voted.");sender.voted = true;sender.vote = proposal;// 如果 `proposal` 超过了数组的范围,// 则会自动抛出异常,并恢复所有的改动。proposals[proposal].voteCount += sender.weight;}
  • 统计投票: 取投票数最多的提案
/// @dev 结合之前所有投票的情况下,计算出获胜的提案。
function winningProposal() public viewreturns (uint winningProposal_)
{uint winningVoteCount = 0;for (uint p = 0; p < proposals.length; p++) {if (proposals[p].voteCount > winningVoteCount) {winningVoteCount = proposals[p].voteCount;winningProposal_ = p;}}
}// 调用 `winningProposal()` 函数以获取提案数组中获胜者的索引,
// 并以此返回获胜者的名称。
function winnerName() external viewreturns (bytes32 winnerName_)
{winnerName_ = proposals[winningProposal()].name;
}
http://www.xdnf.cn/news/19089.html

相关文章:

  • Java 多线程环境下的全局变量缓存实践指南
  • jwt原理及Java中实现
  • Ckman部署clickhouse
  • 5.2 I/O软件
  • 横扫SQL面试——流量与转化率分类
  • C++《哈希表》
  • Unity游戏打包——iOS打包pod的重装和使用
  • Servlet 注解:简化配置的完整指南
  • 大模型微调示例四之Llama-Factory-DPO
  • 若依cloud集训总结
  • 汉字这颗穿越时空的智慧之光,在未来绽放出更加耀眼的光芒
  • 深入解析Java并发编程与单例模式
  • 文件系统挂载详细分析(《图解Linux内核》虚拟文件系统篇笔记三)
  • 神经网络为何能 “学习”?从神经元到深度学习模型的层级结构解析
  • 打破存储局限:CS 创世 SD NAND 如何优化瑞芯微(RK)与北京君正平台的贴片式 SD 卡性能
  • 【C++成长之旅】C++入门基础:从 Hello World 到命名空间与函数重载的系统学习
  • Bscan Bonding Chain
  • 印度尼西亚数据源 PHP 对接文档
  • Mysql——分库分表
  • Redis发布订阅:实时消息系统的极简解决方案
  • 从数字到价值:ESG评级的深层变革
  • Linux827 测试
  • 计算机日常答疑,一起寻找问题的最优解
  • LeetCode算法日记 - Day 24: 颜色分类、排序数组
  • PyTorch图像预处理完全指南:从基础操作到GPU加速实战
  • 完整实验命令解析:从集群搭建到负载均衡配置(2)
  • [vcpkg] Windows入门使用介绍
  • day22 回溯算法part01
  • 服务器类型与TCP并发服务器构建(SELECT)
  • 设计模式:桥接模式(Bridge Pattern)