在区块链上开发可更新的智能合约

如何升级或者更新智能合约? 如果合约发送方想要有一种方法来升级智能合约代码,以便账户数据和其他东西接通,可以有什么办法吗?可以在不改变合约地址的情况下进行,还是总是需要新的地址? 是否存在annex机制,在不需要重写的情况下向智能合约中添加一些新的功能? 问题解答 一旦合约已经部署在区块链中,它就是最终版了并不能再被改变。当然,可以通过允许原始代码改变某些参数,来做些改变。 更新合约的一种方法是使用版本控制系统。例如... 阅读详情

由于区块链不可篡改的特性,智能合约一旦部署在区块链上,其执行的逻辑就无法再更改。长期来看,这个重要的特性反而限制了智能合约的弹性和发展。

接下来要介绍如何设计及部署合约才能让合约在需要时可以更新。但这里的更新意思不是修改已经部署的合约,而是部署新的合约、新的执行逻辑但同时能继续利用已经存在的资料。

首先要知道的是Ethereum Virtual Machine(EVM)要知道如何执行合约的那个函数。合约最后都会被编译成字节码,而你发起一个transaction要执行合约里的某个函数时,交易里的数据同样也是字节码,而不是人看得懂的函数名称。 以一个简单的合约为例:


contract Multiply {
    function multiply(int x, int y) constant returns(int) {
        return x*y; 
    }
}

编译完的二进制码:


6060604052341561000c57fe5b5b60ae8061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633c4308a814603a575bfe5b3415604157fe5b605e60048080359060200190919080359060200190919050506074565b6040518082815260200191505060405180910390f35b600081830290505b929150505600a165627a7a72305820c40f61d36a3a1b7064b58c57c89d5c3d7c73b9116230f9948806b11836d2960c0029

如果你要执行multiply函数,算出8*7等于多少,你的transaction里的数据是 0x3c4308a800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000007 
分成三部分: 第一个是四个字节的3c4308a8,第二和第三个分別是32个字节长的参数,8和7。

3c4308a8是multiply函数的signature(签名),是取函数名称和参数类型使用sha3取前四个byte而得到(不包含0x):


sha3("multiply(int256,int256)"));
//0x3c4308a8851ef99b4bfa5ffd64b68e5f2b4307725b25ad0d14040bdb81e3bafc sha3("multiply(int256,int256)")).substr(2,8);
//3c4308a8

EVM就是靠函数的signature来知道该执行那个函数的。在合约编译完的字节码里查询也能找到这个signature。

接下来要介紹Solidity里的三种调用方式:call、callcode和delegatecall。

  • call:一般的调用都是这种方式,执行背景跳到下一个函数的环境(这里的环境是指msg的值和合约的Storage)。如果被调用的是不同合约的函数那么变换成被调用的合约的环境,且msg.sender编程调用者。
  • callcode:和call相同,只是将被调用函数搬到调用者的环境里执行。
    假设A合约的x函数用callcode方式调用B合约的y函数,就会在A合约里执行y函数,使用A的参数,所以如果y函数里修改某个参数的值且这个参数的名称刚好和A的某个参数名称一致,则A的该参数就会被修改。就把它想像成A多了一个y函数并执行。
  • delegatecall:和callcode相同,都是把被调用的函数搬到调用者的环境里执行,只是在msg.sender的值上有区别。
    来看一个例子:加入A合约用delegatecall的方式调用B合约的函数,B合约的函数接下用callcode或call的方式调用C合约的函数,那么函数里看到的msg.sender会是B;但如果B改用delegatecall的方式调用C合约的函数的话,那么函数里看到的msg.sender会是A。就把它想像成把msg相关的值保持不变传递下去就ok了。

接下来实际来看一下delegatecall的效果:

contract Plus {
    int z;
    function plus(int x, int y) {
        z = x+y;
    }
}
contract Multiply {
    int public z;
    function multiply(int x, int y) {
        z = x*y;
    }
    function delegateToPlus(address _plus, int x, int y) {
        _plus.delegatecall( bytes4(sha3("plus(int256,int256)")) ,x ,
        y);
    }
}

部署并按顺序执行Multiply的multiply和delegateToPlus并观察z值的变化:

可以看到执行delegatecall之后z的值变成是8+7。 所以如果要让我们未来可以改变执行逻辑的话怎么写代码呢?

contract Plus {
    int z;
    function plus(int x, int y) { //sig:"0xccf65503"
        z = x+y;
    }
}
contract Multiply {
    int z;
    function multiply(int x, int y) { //sig:"0x3c4308a8"
        z = x*y;
    }
}
contract Main {
    int public z;
    function delegateCall(address _dest, bytes4 sig, int x, int y) {
        _dest.delegatecall(sig, x , y);
    }
}

我们将合约的地址和函数的signature当做参数传递给delegateCall去执行,假设原本是用Plus合约的执行路基,现在我们更新成Multiply合约:

0x4429 是Plus合约的地址, 0xe905 是Multiply合约的地址。
我们以后只要给它改变后的函数signature和合约地址就可以使用新的执行逻辑了!

但如果合约不是只给一个人使用的话,应当在更新合约的時候所有参与的人都必须要更新新合约的位置。这时候可以用一个合约来帮助我们导到新的合约位置,就像路由器似的,我们统一发送(还是以delegatecall的形式)到路由合约,再由路由合约帮我们导到正确的位置,未来更新合约就只需要更新路由合约的资料即可。

contract Upgrade {
    mapping(bytes4=>uint32) returnSizes;
    int z;
    
    function initialize() {
        returnSizes[bytes4(sha3("get()"))] = 32;
    }
    
    function plus(int _x, int _y) {
        z = _x + _y;
    }
    function get() returns(int) {
        return z;
    }
}
contract Dispatcher {
    mapping(bytes4=>uint32) returnSizes;
    int z;
    address upgradeContract;
    address public dispatcherContract;
    function replace(address newUpgradeContract) {
        upgradeContract = newUpgradeContract;
        upgradeContract.delegatecall(bytes4(sha3("initialize()")));
    }
    function() {
        bytes4 sig;
        assembly { sig := calldataload(0) }
        var len = returnSizes[sig];
        var target = upgradeContract;
        
        assembly {
            calldatacopy(mload(0x40), 0x0, calldatasize)
            delegatecall(sub(gas, 10000), target, mload(0x40),
                         calldatasize, mload(0x40), len)
            return(mload(0x40), len)
        }
    }
}
contract Main {
    mapping(bytes4=>uint32) public returnSizes;
    int public z;
    address public upgradeContract;
    address public dispatcherContract;
    
    function deployDispatcher() {
        dispatcherContract = new Dispatcher();
    }
    
    function updateUpgrade(address newUpgradeContract) {
        dispatcherContract.delegatecall(
            bytes4( sha3("replace(address)")), newUpgradeContract
        );
    }
    
    function delegateCall(bytes4 _sig, int _x, int _y) {
        dispatcherContract.delegatecall(_sig, _x, _y);
    }
    
    function get() constant returns(int output){
        dispatcherContract.delegatecall(bytes4( sha3("get()")));
        assembly {
            output := mload(0x60)
        }
    }
}

执行顺序:
1. 执行Main.deployDispatcher() 部署路由合约
2. 部署upgrade合约并将其address当做Main.updateUpgrade()的参数传入用来更新upgrade合约的地址资料。
3. 执行Main.delegateCall(),参数是plus(int256,int256)的signature和任意两个值。
4. 执行Main.get(),由delegatecall去调用upgrade合约的get函数,回传相加完的z值。因为是delegatecall,所以这个z值其实是Main合约自己的,upgrade合约的z值是零。

如果delegatecall调用的函数有返回值的话,必须要用assembly来手动获得返回值,因为delegatecall和call一样,只会回传true of false来代表执行是否成功。Dispatcher在调用是同样也是用assembly code。
但因为是用assembly手动获得返回值,因此前提是返回值的长度必须是固定且已知的,所以当我们在步骤2更新upgrade合约时,Dispatcher合约同时去调用upgrade合约的initialize()函数,upgrade合约在initialize函数里将它所有会有返回值的函数的返回值大小写入returnSizes中,之后如果调用具有返回值的函数时,Dispatcher就知道返回值的大小了。

這个还有一个重点是参数定义的顺序
因为合约执行要用参数值的时候,它会到对应的Storage位置去找。所以如果你的合约参数定义像這樣子
upgrade:
int x
int y
 — — — — 
Dispathcer:
int x
int y
 — — — — 
Main:
int x
int abc
int y
当upgrade合约的函数需要用到x和y的值的时候,它会找不到y,因为Storage是Main的。

分享两个教程和一些免费资料给读者:

一个适合区块链新手的以太坊DApp开发教程:

http://xc.hubwiz.com/course/5a952991adb3847553d205d1

一个用区块链、星际文件系统(IPFS)、Node.js和MongoDB来构建电商平台:

http://xc.hubwiz.com/course/5abbb7acc02e6b6a59171dd6

收集整理了一些免费区块链、以太坊技术开发相关的文件,有需要的可以下载,文件链接:

1. web3.js API官方文档中文版:https://pan.baidu.com/s/1hOV9hEzi7hFxJCL4LTvC6g
2. 以太坊官方文档中文版     :https://pan.baidu.com/s/1ktODJKLMBmkOsi8MPrpIJA
3. 以太坊白皮书中文版       :https://pan.baidu.com/s/1bzAFnzJ35hlQxJ2J4Oj-Ow
4. Solidity的官方文档中文版 :https://pan.baidu.com/s/18yp9XjEqAHpiFm2ZSCygHw
5. Truffle的官方文档中文版  :https://pan.baidu.com/s/1y6SVd7lSLUHK21YF5FzIUQ
6. C#区块链编程指南         :https://pan.baidu.com/s/1sJPLqp1eQqkG7jmxqwn3EA
7. 区块链技术指南          :https://pan.baidu.com/s/13cJxAa80I6iMCczA04CZhg
8. 精通比特币中文版        :https://pan.baidu.com/s/1lz6te3wcQuNJm28rFvBfxg
9. Node.js区块链开发        :https://pan.baidu.com/s/1Ldpn0DvJ5LgLqwix6eWgyg
10. geth使用指南文档中文版   :https://pan.baidu.com/s/1M0WxhmumF_fRqzt_cegnag
11. 以太坊DApp开发环境搭建-Ubuntu   : https://pan.baidu.com/s/10qL4q-uKooMehv9X2R1qSA
12. 以太坊DApp开发环境搭建-windows  :https://pan.baidu.com/s/1cyYkhIJIFuI2oyxM9Ut0eA
13. 以太坊DApp开发私链搭建-Ubuntu   : https://pan.baidu.com/s/1aBOFZT2bCjD2o0EILBWs-g
14. 以太坊DApp开发私链搭建-windows  :https://pan.baidu.com/s/10Y6F1cqUltZNN99aJv9kAA


最新论文笔记(+7):SMACS:Smart Contract Access Control Service / IEEE/IFIP DSN 2020 SMACS:Smart Contract Access Control Service.(SMACS:智能合约访问控制服务) 在本篇论文中,作者提出了一种可低成本实现、可更新且精细的智能合约访问控制规则(ACRs)的框架——SMAC。这种框架将昂贵的ACR验证和管理操作的负担转移到了链下的基础架构上,同时仅实现了基于区块链的轻量级基于token的访问控制。SMACS除了简单的访问控制列表之外,还可以轻松地实施规则,从而增强智能合约运行时的安全性。 原文链接:SMACS:Smart Contract Acc 阅读详情

相关推荐

从零开始开发AI Agent:基于大模型的智能体实战指南

### 摘要 本文介绍了AI Agent的开发全流程,从基础概念到实际部署,涵盖大模型集成、工具调用和记忆系统构建等核心技术。通过电商客服案例展示实战应用,并提供调试优化与部署方案,最后展望了AI Agent的未来发展方向,帮助开发者快速掌握智能体开发技能。

ghs_gss的博客 4860

区块链智能合约开发

合约是经过双方或多方同意,约定立即执行或在将来执行一项交易的法律文件。因为合约是法律文件,所以它具有强制性和可执行性。合约应用的场景很多,例如:一个人和保险公司签订合同购买健康险,一个人从另外一个人手里购买一块土地,个公司出售股权给另外一家公司。

2201_76041915的博客 6223

STM32_WS2811驱动

STM32的WS2811驱动

健身房 2839

区块链智能合约的开发

区块链智能合约的开发是指使用特定的编程语言在区块链平台上创建、测试和部署自动执行的协议。总而言之,区块链智能合约的开发是一个涉及多个步骤的复杂过程,需要开发者具备扎实的编程基础、对区块链技术的深入理解以及高度的安全意识。在将智能合约部署到生产环境之前,强烈建议聘请专业的第三方安全审计机构对合约代码进行全面的安全审查。根据你的项目需求,使用选定的编程语言编写智能合约代码。这涉及到定义合约的状态变量、函数、事件以及控制合约逻辑的流程。不同的区块链平台支持不同的智能合约功能和编程语言。

zhaoyin0335的博客 983

【STM32/GD32】Keil uVision生成bin文件:从编译选项到Bootloader升级实战

本文详细讲解了如何在Keil uVision中配置STM32/GD32工程,使其在编译后自动生成Bootloader升级所需的bin文件。通过解析fromelf工具的使用、构建后命令的配置以及内存布局规划,深入阐述了bin文件在固件升级中的核心作用,并提供了串口Bootloader的实战框架与常见问题解决方案。

weixin_29190169的博客 391

更改训练好的yolo模型中的class类名,无需重新训练

本文介绍了如何在不重新训练YOLO模型的情况下修改其类名的技巧。关键点在于理解YOLO类名存储逻辑:类名列表(names)存储在配置文件中(.yaml),而非权重文件(.pt)。通过修改配置文件的类名列表(保持类别数量nc不变),即可实现类名更新。具体步骤包括:1)准备修改后的配置文件;2)加载模型并更新类名;3)验证推理结果。该方法适用于YOLOv5/YOLOv8等版本,能有效节省开发时间,适用于类名表述调整、多场景复用等需求。注意:增减类别需重新训练,仅修改类名时需确保类别数量一致。

yolo模型训练找我,AI游戏合作找我 878

区块链(二、智能合约的开发)

合约是经过双方或多方约定执行一项交易的法律文件。具有强制性和可执行性。智能合约是按照用户的需求编写的代码,并部署和运行在以太坊虚拟机(EVM)上。智能合约在代码中限定了账户之间的交易规则,有利于通过原子化交易来实现数字资产的转移,也可以用于存储重要数据。智能合约就是由函数构成的小程序,类似面向对象的class类,可以互相调用,就像class类实例化和互相调用。 下面来说明一下智能合约的开发流程。 一、环境 1. 运行(部署)环境 合约可以运行在公共网络(以太坊网络)、测试网络或私有网络。 以太坊:是

funtaster的博客 1万+

光芯片Photodiode 原理,设计与版图

但是光电二极管相对较大,因为需要接收足够的入射光线,此外,光电二极管的厚度比较小,通常位于 1 um 以下(为了波导模式更好地在波导中传输,减少损耗)。从下图中可以看出,当反偏时,即有光在耗尽层被吸收被转换为电流信号时,增加反向偏压几乎不影响反向电流,因此,对于光电二极管来说,反向电压并不影响反向电流的大小。不施加外部电压(开路状态),光生电压直接输出,流出的电流受到抑制,在两端积累一定的电位差,类似太阳能电池,具体特点是噪声低,但响应速度慢。因此,需要尽可能的减少暗电流,以增加元件对光的灵敏度。

u011699626的博客 977

区块链发展和智能合约开发

BTC的主要是用作虚拟货币并存储价值,而ETH也可以实现相同的功能,但是,去中心化的ETH网络还可以实现部分其他的功能,例如创建和运行应用程序、签订智能合同以及进行其他类型的交易,而所有这些功能都是BTC所不具备的,后者只能实现有限的功能。以太坊是一个开放的公共区块链平台,其利用智能合约来实现对用户行为进行约束,通过其衍生的加密货币ETH,来为以太坊网络提供去中心化的以太虚拟机(EVM)来处理P2P的智能合约。以太坊架构分为 7 层,由下至上依次是:存储层、数据层、网络层、协议层、共识层、合约层、应用层。

weixin_39373817的博客 1069

【Docker】一招解决超时镜像超时报错:`ERROR: Get https://registry-1.docker.io/v2/`

Docker 镜像拉取超时或失败并不是 Docker 本身的缺陷,而是网络环境和默认配置在特定场景下的限制所导致的结果。通过本文的分析可以看到,问题的核心往往集中在三个方面:网络访问延迟、DNS 解析速度以及客户端默认超时时间。针对这些问题,最直接、有效的做法是使用国内镜像加速器,这不仅能够显著提升拉取速度,还能保证在企业内网或家庭网络中更加稳定

博客 1027

S7-200SMART PLC中进行MODBUS RTU通信的3种方法(1)

S7-200SMART PLC中进行MODBUS RTU通信的3种方法(1)

Robot_PLC_HMI_Automation 4236

『区块链智能合约』从零构建Ethereum智能合约到实战开发

为什么说现在学习区块链才是最好的时机?区块链技术不只是能开发数字货币,不只是能进行ICO。当我分享一些区块链文章的时候,偶尔总会有人艾特我说,春哥,现在国家都不让炒币了,还弄个毛的区块链啊。我一般会很平静的告诉他,数字货币只是区块链落地产品类型之一,严格来讲,交易所关闭,国家不让ICO是好事,大家会发现,现在国家禁止ICO后,币圈瞬间清净多了,我觉得是好事,因为现在暴露了很多打着ICO牌子裸泳的人,

孔壹学院 4382

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

以太坊可更新智能合约研究与开发综述

原文地址:https://ethfans.org/posts/ethereum-upgradeable-smart-contract-strategies这篇文章是对以太坊可更新智能合约领域里的研究和开发的综述。它意图成为一篇便利的资源帖,集中迄今为止的研究,并推进技术讨论。此外,我已经创建了一个关于不同策略的优缺点比较的简要表格,下面会放出来。如果你正在研究或者开发领域工作或者观摩,请对本文作出...

tianlongtc的博客 709

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

基于后量子密码学:微算法科技(NASDAQ: MLGO)区块链预言机加密可更新方案

例如,在天气数据获取场景中,多个节点从不同气象站获取数据,通过比较数据一致性、时间戳等信息,只有当多数节点确认数据准确后,该数据才会被引入区块链。更新过程中,采用安全多方计算技术,在加密环境下对合约代码和参数进行修改,确保更新过程不影响合约的正常执行,同时防止敏感信息泄露。未来,微算法科技(NASDAQ :MLGO)可深化后量子密码学与区块链预言机的融合深度,推动加密可更新方案向轻量化、低延迟、跨平台方向演进,助力区块链生态在量子计算时代构建更稳固的安全底座,推动分布式技术在更多产业场景实现规模化应用。

MicroTech2025的博客 411

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Web3.js 智能合约开发全流程指南

Web3.js 智能合约开发全流程指南 【免费下载链接】web3.js Ethereum JavaScript API 项目地址: https://gitcode.com/gh_mirrors/we/web3.js ...

gitblog_01144的博客 755

智能合约3.0

摘要: 本文主要谈了智能合约的演变和展望,从传统合同-谈到智能合约1.0->2.0->3.0,分析了各阶段智能合约解决方案的不足性,最后重点论述智能合约3.0需要具备的要素和已有解决方案的优势和独特的应用场景。 现实中合同是写在纸上,要签字盖章才能生效,由于文字的多种含义常常会带来合同双方的不同理解,大家为此而产生不少纠纷;如果把纸上合同变成程序代码,问题就简单很多,因为代码不会产生...

老杨QQ122209017的博客 1814

分享可更新模型(SUM)在区块链上:微软0xDeCA10B项目指南

--- ## 项目介绍 **分享可更新模型(SUM)在区块链** 是一个旨在通过区块链托管和训练公共机器学习模型的框架。该框架提倡免费获取模型预测,并采用三步验证机制添加数据。数据处理存储于区块链中以确保透明度和持久性。激励机制负责验证数据添加请求并可能实施奖励措施。任何人均可免费查询模型进行预测。更多信息可通过项目博客及发表在IEEE国际区块链会议上的论文获取。 ## 项目快速启动 为了

gitblog_00045的博客 448

solmate: 智能合约开发的高效构建块

solmate 是一个由 优快云 公司开发的现代、有主张且优化了燃料消耗(gas)的智能合约构建块集合。该项目主要使用 Solidity(89.2%)和 Julia(10.8%)两种编程语言开发,专注于为智能合约开发者提供一系列经过优化的标准合约和工具库。 ## 2. 核心功能 solmate 提供了以下核心功能: - **合约授权(auth)**: 包括简单单一所有者授权(Owned)和...

gitblog_00647的博客 841

在區塊鏈上建立可更新的智慧合約(二)

這篇介紹用library的方式來建立可更新的合約邏輯。 Library Library是另外一種形式的contract,宣告方式也幾乎一樣: Library libA{}。Library會被部署在鏈上,有一個專屬的address,任何人都可以呼叫它,但是Library 1. 不能持有ether 2. 沒辦法儲存任何資料,Library裡面只有函式(動作)。合約呼叫Library是用de

omnispace的博客 242

代码即权力:DApp如何用一行智能合约改写全球规则?

2025年的互联网世界,正经历一场静默的革命。传统App的服务器集群逐渐被区块链节点取代,用户数据从中心化数据库迁移至分布式账本,而交易逻辑则由智能合约自动执行——这一切,正通过去中心化应用(DApp)的普及悄然实现。从DeFi协议每日处理超千亿美元的交易,到链游玩家通过NFT资产月入数万美元;

2501_91377248的博客 947

智能合约库(Solmate)

Solmate是由开发者社区中的贡献者创建的开源智能合约库,主要使用Solidity(89.2%)和Julia(10.8%)两种编程语言开发。 提供合约授权、权威管理、代币、工具库等核心功能。在合约授权方面,有简单单一所有者授权和灵活可更新的授权模式;权威管理方面,支持基于角色的权威管理;代币方面,包含最小化且现代的包装以太实现、高效的ERC20和EIP-2612实现等;工具库方面,提供更经济的存储读写、确定性地址部署、数值字符串转换等实用功能。

weixin_43156294的博客 2181

EOS智能合约编译&部署

跟随大家学习编程语言一样,每次都会首先写一段代码,打印“hello,wrold”。通过对EOS的学习,今天将编译一个简单的hello智能合约部署到EOS私有链上。 1.EOS智能合约简介 之前学习过ETH,下面我将两者的智能合约进行简单的对比。 ETH EOS 编程语言 solidity 语言开发,类似js语言 C++ 编译工具 solc eosio-cpp 部署方式 h...

u010304442的博客 1653
上一篇: web3.js中estimateGas如何计算智能合约消耗的gas量
下一篇: 深入以太坊智能合约 ABI
落叶无声9
博客等级 码龄12年 443粉丝 343原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值