Fabric1.4配置总览及解读

Fabric1.4配置总览及解读

Fabric网络中,从为Fabric中各节点产生证书到链上通道的创建,再到每个节点启动,均需要配置,这些配置信息为Fabric网络提供稳定的运行状态,本节将从搭建Fabric网络的角度出发,分别对Fabric中的证书配置,通道配置以及各节点启动配置进行解析。读者通过本篇博客的学习将掌握fabric网络中各节点配置文件中的各个配置项的作用,以及通过修改各个配置来搭建满足所需的Fabric网络。

简介

作为fabric的使用者,可以通过修改配置来限定各个fabric节点的行为,也可以通过修改配置来管理包括节点身份,通道配置等多种资源,配置的了解在fabric使用过程中是必不可少的一环。

为Fabric节点生成组织身份信息

对于访问成员,Fabric网络通过该成员的证书与密钥来对该成员进行认证与管理,Fabric基于其联盟链的身份,网络中用户结构由联盟中的各个组织到组织下的各个节点,再到节点下的各个用户成员组成,各个组织节点以及节点下用户的证书及密钥可以通过使用fabric官方提供的二进制工具cryptogen(crypto genertor)以及配置文件来生成,这里一般生成的节点下用户信息是有限个数的,节点下用户的证书信息可以通过fabric提供的PKI服务(fabric-ca)来为后续联盟节点下用户申请证书。

生成联盟组织身份的配置文件解析

搭建Fabric网络第一步就是要为联盟节点生成证书以及密钥,首先需要配置生成联盟组织身份的配置文件,然后配合二进制工具cryptogen来生成证书,配置文件内容如下代码块所示,每行配置上均附上配置说明。

OrdererOrgs:                #orderer集群的节点所属组织
  - Name: Orderer		    #组织的名称
    Domain: example.com		#组织的命名域
    Specs:			        #这里指定orderer组织的规格
      - Hostname: orderer	#这里指定orderer组织内包含的节点名字
      - Hostname: orderer1
      - Hostname: orderer2
PeerOrgs:		            #peer集群的节点所属组织
  - Name: Org1			    #组织名称
    Domain: org1.example.com#组织命令域
    EnableNodeOUs: true     #是否根据证书中的OU字段来判断访问者的角色
    Template:	            #当前peer组织的模版配置
      Count: 2				#当前peer组织的模版数量,这里为2个peer节点
    Users:					#当前peer组织的用户证书配置,
      Count: 2              #当前peer组织产生证书的用户个数,这里为产生两个用户的证书
  - Name: Org2
    Domain: org2.example.com
    EnableNodeOUs: true
    Template:
      Count: 2
    Users:
      Count: 2    

以上配置文件创建的联盟链包含三个组织,一个orderer组织,两个peer组,orderer组织内包含三个节点,分别为orderer,orderer1,orderer2,peer组织为Org1,Org2两个组织,每个组织下均包含两个节点为peer0,peer1。

  • EnableNodeOUs字段为true时,启动NodeOU,会在该组织证书目录下的msp目录下生成config.yaml文件,文件内指定了该节点的ca证书的位置,并根据该ca证书来判断该节点的OU类型,这时Fabric网络中访问者的身份可以通过证书中OU字段来判断,OU种类有client,peer,admin以及orderer,Fabric通过访问者的身份来决定访问者的权限,比如在安装链码或者实例化链码时,需要访问者的角色为peer;而涉及到对通道进行配置管理的时候,需要访问者的角色为admin。
  • peer与orderer组织的规格可以使用Specs或者Template来进行配置,两者的区别为,Specs可以规定每个节点的名称,而Template只能指定节点的个数,比如peer组织指定template为2,则两个节点为peer0,peer1,根据数量依次后排。
  • 关于为peer组织产生用户数量的字段Users,这里指定的为产生节点用户的数量,这里的数量并不包含admin用户,admin用户时默认产生的,后面如果user的个数不够用,可以使用fabric提供的PKI服务(fabric-ca)来生成。
二进制工具cryptogen的使用

cryptogen主要用来为Fabric联盟生成身份信息,主要的应用场景有两方面,一方面是启动一个新的联盟链时,为联盟成员生成身份信息;另一方面是针对已有的联盟链,需要拓展整个联盟,比如为联盟添加新组织,为旧组织添加新的节点等,可以在不影响已有的联盟链证书情况下,使用cryptogen工具为联盟添加的新组织生成身份信息。

  • cryptogen支持的子命令如下代码块所示:
usage: cryptogen [<flags>] <command> [<args> ...]

Utility for generating Hyperledger Fabric key material

Flags:
  --help  Show context-sensitive help (also try --help-long and --help-man).

Commands:
  help [<command>...]. #查看cryptogen的帮助信息
    Show help.

  generate [<flags>] #子命令生成身份信息
    Generate key material

  showtemplate # 在当前目录下生成模版配置文件
    Show the default configuration template

  version #查看当前cryptogen二进制工具的版本
    Show version information

  extend [<flags>] #继承已有的网络为新的节点生成身份信息
    Extend existing network

为联盟成员生成身份信息需要用到generate子命令,这个命令中需要指定配置文件的位置以及生成证书目录的位置,配置文件的位置是必须的,如果不指定,会根据模版文件进行生成身份信息;生成证书目录的位置不是必要的,不指定的话,会在当前目录生成crypto-config的目录,生成身份信息的命令示例如下:

cryptogen generate --config ./crypto-config.yaml --output crypto-config

为已有联盟添加的新成员生成身份信息需要用到extend子命令,这个命令需要指定已有的证书目录以及最新的配置文件的位置,这两者均是必要的,命令示例如下:

cryptogen extend --config ./crypto-config.yaml --input crypto-config

为Fabric网络生成通道配置相关文件

Fabric联盟中的成员是通过通道来进行共享数据的,不同联盟之间也通过通道来进行数据隔离,在Fabric网络节点启动前,需要配置通道文件,配合二进制工具configtxgen来生成通道配置块,创世区块以及组织的锚节点更新文件,这里从通道配置文件解析以及二进制工具configtxgen的使用两方面来展开叙述。

通道配置文件解析

搭建Fabric网络,在为联盟成员生成身份信息后,接下来要进行通道配置相关文件的生成,首先配置通道配置文件,配合二进制工具configtxgen来生成通道相关文件文件,通道配置文件文件内容如下代码块所示,每行配置均附上配置说明。

---
Organizations:  #通道内包含的组织的配置信息,peer组织以及orderer的配置
    - &OrdererOrg      
        Name: OrdererOrg     #排序组织组织名称
        ID: OrdererMSP    #MSPID 
        MSPDir: crypto-config/ordererOrganizations/example.com/msp #排序组织的MSP本地路径
        Policies:    #组织内权限配置
          Readers:  #读权限
              Type: Signature     #策略类型为非组合签名策略
              Rule: "OR('OrdererMSP.member')"     #满足排序组织任意成员的签名
          Writers:     #写权限
              Type: Signature 
              Rule: "OR('OrdererMSP.member')"
          Admins:     #管理权限
              Type: Signature
              Rule: "OR('OrdererMSP.admin')" #满足排序组织任意管理员签名
    - &Org1
        Name: Org1MSP     #org1组织MSP的名称
        ID: Org1MSP     #MSPID
        MSPDir: crypto-config/peerOrganizations/org1.example.com/msp              #Org1组织的MSP本地路径
        AnchorPeers: #Org1组织的锚节点配置,用来组织间进行通信
            - Host: peer0.org1.example.com    #节点名称
              Port: 7051    #节点暴露的端口
        Policies:    #Org1组织的权限配置
          Readers: 
              Type: Signature 
              Rule: "OR('Org1MSP.admin','Org1MSP.peer','Org1MSP.client')" #满足Org1组织admin,peer,client中任意成员的签名,这里也可以解释为满足Org1组织内非orderer角色的任意成员签名
          Writers:
              Type: Signature
              Rule: "OR('Org1MSP.admin','Org1MSP.client')"     #满足Org1组织admin,client中任意成员签名
          Admins:
              Type: Signature
              Rule: "OR('Org1MSP.admin')" #满足只Org1组织任意admin成员的签名
    - &Org2
        Name: Org2MSP
        ID: Org2MSP
        MSPDir: crypto-config/peerOrganizations/org2.example.com/msp
        AnchorPeers:
            - Host: peer0.org2.example.com
              Port: 9051
        Policies:
          Readers:
              Type: Signature
              Rule: "OR('Org2MSP.admin','Org2MSP.peer','Org2MSP.client')"
          Writers:
              Type: Signature
              Rule: "OR('Org2MSP.admin','Org2MSP.client')"
          Admins:
              Type: Signature
              Rule: "OR('Org2MSP.admin')"          
Capabilities:    #以下定义了关于通道服务,排序服务,应用服务对于orderer以及peer版本的兼容性指定,以下三种配置将在后面被引用
    Channel: &ChannelCapabilities    #通道范围内对于orderer以及peer版本的兼容性
        V1_3: true    #对于高于v1.3版本的orderer以及peer的镜像均被兼容,低于v1.3版本将不被兼容
    Orderer: &OrdererCapabilities    #对于排序节点orderer的版本兼容性指定
        V1_1: true    #低于v1.1版本的orderer在排序服务上不被兼容
    Application: &ApplicationCapabilities    #对于与应用之间进行交互的peer节点的版本兼容性的指定
        V1_3: true    #低于v1.3的peer节点在应用上不被兼容
        V1_2: false  #这里因为指定了V1_3为true,故这一行配置有无均可
        V1_1: false    #这里因为指定了V1_3为true,故这一行配置有无均可
Application: &ApplicationDefaults    #应用服务的默认配置,包含默认反问控制策略,对于orderer,peer的版本兼容配置
    Organizations:
    Policies:
        Readers: #读策略
            Type: ImplicitMeta    #代表一个组合策略,组合策略由多个signature的签名策略组成
            Rule: "ANY Readers"    #这里指满足任意一个具有读权限的访问者的签名即可
        Writers:    #写策略
            Type: ImplicitMeta     #组合策略
            Rule: "ANY Writers"   #满足任意一个具有写权限的访问者的签名即可
        Admins:    #管理权限
            Type: ImplicitMeta    #组合策略
            Rule: "MAJORITY Admins"    #满足大多数管理权限用户的签名
    Capabilities: 	#这里是关于应用服务对于peer的版本兼容配置
        <<: *ApplicationCapabilities     #引用了上面的默认配置,即peer版本不能低于v1.3
Orderer: &OrdererDefaults   #orderer部分的配置,主要用于产生第一笔配置交易以及创世块的相关参数,这部分会在profile处被引用
    OrdererType: solo    #orderer达成共识的方式,有solo,kafka,etchraft
    Addresses:    #orderer地址
        - orderer.example.com:7050
    BatchTimeout: 2s    #这里指定了orderer切割区块的超时时间
    BatchSize:    #这里指定了orderer切割区块大小的阈值
        MaxMessageCount: 200   #这里指定了一个区块内的最大的交易数量为200笔交易
        AbsoluteMaxBytes: 2 MB    #这里指定了一个区块的大小的阈值,超过这个大小后,即切割batch,生成区块
        PreferredMaxBytes: 512 KB    #这里指定了单笔交易成块的阈值,即如果有一笔交易的大小超过当前阈值,则此笔交易单独成块。
    Kafka:     #kafka集群的配置
        Brokers:
        - 127.0.0.1:9092
    Organizations:  #排序服务的策略配置
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        BlockValidation:
            Type: ImplicitMeta
            Rule: "ANY Writers"
Channel: &ChannelDefaults    #通道默认配置,在下面Porfile处被引用
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
    Capabilities:
        <<: *ChannelCapabilities    #引用了通道服务对peer,orderer的版本兼容配置
Profiles:    #配置模版部分,这部分中大部分会引用上面的配置,根据这里的key来产生通道文件,创世块等
    TwoOrgsOrdererGenesis:    #这部分为配置orderer的排序服务,用来产生创世区块文件,文件内主要包含orderer的组织配置,orderer的共识选型,这里的共识类型为raft.
        <<: *ChannelDefaults  #这里引用上述的通道默认配置
        Capabilities:    #这里引用了上面关于通道服务对peer,orderer版本兼容的配置,这里因为ChannelDefaults中已经引用过ChannelCapabilities,这里并不需要配置,但是如果这里引用其他的配置,会覆盖原有的配置
            <<: *ChannelCapabilities
        Orderer:    #这里指定了系统通道的配置信息
            <<: *OrdererDefaults    #这里引用了上面关于排序服务的配置
            OrdererType: etcdraft    #这里是关于排序服务的共识类型的配置,由于OrdererDefaults中选择的共识为solo,这里再此配置,则将会把solo的配置覆盖掉
            EtcdRaft:    #选择raft作为共识算法
                Consenters:    //raft共识内的所有节点的域名,端口以及通信用的证书
                - Host: orderer.example.com
                  Port: 7050
                  ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
                  ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
                - Host: orderer1.example.com
                  Port: 8050
                  ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.crt
                  ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.crt
                - Host: orderer2.example.com
                  Port: 9050
                  ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt
                  ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt            
            Addresses:
                - orderer0.example.com:7050
                - orderer1.example.com:8050
                - orderer2.example.com:9050
            Organizations:    #系统通道中包含的组织
            - *OrdererOrg    #引用了上面orderer组织的配置
            Capabilities:
                <<: *OrdererCapabilities    #引用了排序服务对peer,orderer节点版本的兼容配置
        Application:    #指定应用通道的配置
            <<: *ApplicationDefaults    #引用了上面应用通道的配置
            Organizations:   #指定应用通道包含的组织以及联盟
            - <<: *OrdererOrg    #引用orderer组织的配置
        Consortiums:    #指定应用通道下的联盟
            SampleConsortium:   #这里配置的为应用通道联盟
                Organizations:
                    - *Org1    #引用Org1组织的配置
                    - *Org2.  #引用Org2组织的配置
    TwoOrgsChannel:  #应用通道配置
        Consortium: SampleConsortium   #引用通道上面配置的联盟
        <<: *ChannelDefaults    #通道默认配置
        Application:    #应用通道的配置信息
            <<: *ApplicationDefaults    #默认的应用配置
            Organizations:  #应用通道的组织信息
                - *Org1
                - *Org2
            Capabilities:
                <<: *ApplicationCapabilities    #引用的应用服务对于peer,orderer版本兼容性

由于篇幅的原因,对于通道配置,做一下几点补充:

  • 关于Policies策略部分,在Fabric1.2中实现,官方称之为ACL(Access control list),这些策略均与fabric网络中的各种资源挂钩,用户与Fabric交互,需要通过,系统链码,用户链码以及事件流等,这些均属于访问控制策略下管理的资源,访问控制策略可以通过两种方式构建,一种为Signature策略,另一种为ImplicitMeta策略,Signature为正常的签名策略,会指定组织内的哪些角色或者成员来签名,这里角色指启动NodeOU后的peer,client,admin等,ImplicitMeta策略由多个SIgnature策略作为子策略组成,一般需要多个签名才能满足策略。
  • 关于Capabilities字段,在Fabric的1.1.0版本中实现,官方主要是为了避免不同不兼容版本的orderer,peer的混用,比如,对于每笔交易的校验时,不兼容的版本peer会产生不同的结果,老版本的peer会因为识别不了交易而导致交易的失败,从而关于这笔交易的键值对在新旧版本的peer的世界状态中就会不同,这里的版本兼容性不不指fabric中的各种特性,如果想要使用fabric中的某一个特性,需要参照官方文档找到合适的版本,比如想使用raft共识,需要使用orderer版本为1.4.1以上的才可以。
Fabric网络中各节点的配置解析

Fabric网络中包含peer,orderer,fabric-ca等节点,节点的配置决定了节点的行为,想要一个定制化的Fabric网络,了解节点配置的作用是必要的。本节将从orderer, peer的docker启动配置开始,对每个环境变量的作用进行解析。

Orderer节点的docker配置解析

orderer节点的配置解析,下面代码块为orderer1节点的docker配置文件,每行配置均附上解释。

version: '2'
volumes:
  orderer1.example.com:
services:
  orderer1.example.com:    #orderer1服务名称
    container_name: orderer1.example.com    #orderer1的容器名称
    image: hyperledger/fabric-orderer:latest    #容器启动使用的基础镜像
    environment:    #环境变量
      - FABRIC_LOGGING_SPEC=INFO    #orderer1节点打印日志的级别,常用的有info, debug 
      - GODEBUG=netdns=go    #这里指定了DNS解析使用go解析器,这样DNS请求的阻塞只消耗一个groutine,有效减小消耗资源
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0   #服务绑定的监听地址,一般为全网(0.0.0.0),也可以指定特定的网络接口地址
      - ORDERER_GENERAL_GENESISMETHOD=file    #指定持久化数据的方式,fabric1.4中一般为file,也可以指定为内存
      - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block    #指定创世块文件的位置,创世块文件由configtx.yaml配合二进制工具configtxgen产生
      - ORDERER_GENERAL_LOCALMSPID=OrdererMSP    #orderer的MSPID,在configtx.yaml中配置
      - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp    #orderer的msp路径,
      # enabled TLS
      - ORDERER_GENERAL_TLS_ENABLED=true     #与其他节点通信是否开启tls
      - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key    #tls私钥路径
      - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt    #tls证书路径
      - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]   #根Ca证书列表,用于校验客户端身份
      - ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt    #双向TLS认证时,作为服务端证书的文件路径
      - ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key    #双向TLS认证时,作为客户端私钥的文件路径
      - ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]    #信任的根证书列表
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric    #dock er内部工作路径
    command: orderer    #启动命令
    volumes:    
      - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block    #将产生的创世块文件映射到docker内部
      - ./crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/msp:/var/hyperledger/orderer/msp    #将orderer1的msp目录映射到docker内部
      - ./crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/:/var/hyperledger/orderer/tls    #将orderer1的tls目录映射到dock er内部
      - orderer1.example.com:/var/hyperledger/production/orderer    #将orderer产生的配置块文件映射到本地,这里需要注意,重新启动fabric网络时,需要清理本地持久化的文件,否则,旧的文件信息会加载到新的fabric网络中,导致创建通道等操作的失败。
    ports:
      - 7050:7050    #提供服务的端口

peer节点的配置解析,下面代码块为peer1节点的docker配置文件,每行配置均附上解释。

version: '2'
volumes:
  peer1.org1.example.com:
services:
  peer1.org1.example.com:     #docker服务命令
    container_name: peer1.org1.example.com    #docker启动容器名
    hostname: peer1.org1.example.com    #peer1节点域名
    image: hyperledger/fabric-peer:latest    #docker启动使用的基础镜像
    environment:
      - CORE_LEDGER_STATE_STATEDATABASE=CouchDB   #peer使用的状态数据库类型,有couchdb,leveldb两种,couchdb支持富查询,leveldb只支持组合键
      - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb0:5984    #指定状态数据库couchdb的域名以及端口
      # The CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME and CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD
      # provide the credentials for ledger to connect to CouchDB.  The username and password must
      # match the username and password set for the associated CouchDB.
      - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=    #指定couchdb连接的用户名,这里与couchdb配置保持一致即可,可以为空
      - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=    #指定couchdb连接的密码,这里与couchdb配置保持一致即可,可以为空
      - CORE_PEER_ID=peer1.org1.example.com    #peerID,在fabric网络中唯一标识其身份
      - GODEBUG=netdns=go    #这里指定了DNS解析使用go解析器,这样DNS请求的阻塞只消耗一个groutine,有效减小消耗资源
      - CORE_PEER_ADDRESS=peer1.org1.example.com:7051    #指定pe er服务域名以及端口
      - CORE_PEER_CHAINCODELISTENADDRESS=peer1.org1.example.com:7052    #链码启动监听地址
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:7051     #对组织外部的节点公布的连接地址,不设置则对于其他组织不可见
      - CORE_PEER_LOCALMSPID=Org1MSP       #peer组织的MSPID
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock    #Docker Daemon地址
      - FABRIC_LOGGING_SPEC=INFO     #peer日志级别
      - CORE_PEER_GOSSIP_USELEADERELECTION=true    #使用自动动态选举,不能与CORE_PEER_GOSSIP_ORGLEADER同时设置为true
      - CORE_PEER_GOSSIP_ORGLEADER=false    #设置本节点是否为leader节点   不能与CORE_PEER_GOSSIP_USELEADERELECTION同时设置为true
      - CORE_PEER_TLS_ENABLED=true     #通信是否启用tls
      - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt     #服务使用的TLS证书
      - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key   #服务使用的TLS私钥
      - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt    #信任的根ca证书列表,用于校验客户端身份
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer     #docker工作路径
    command: peer node start     #docker启动命令
    volumes:
      - /var/run/:/host/var/run/    #主要是将docker.sock文件映射至docker内
      - ./crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/fabric/msp     #将peer1的msp证书目录映射到docker内
      - ./crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls:/etc/hyperledger/fabric/tls    #将peer1的tls证书目录映射到dock er内
      - peer1.org1.example.com:/var/hyperledger/production    #将peer1持久化的数据块映射至本地
    ports:
      - 7051:7051  #暴露7051	用于通信
      - 7052:7052    #暴露7052 用于监听链码请求

以上配置均按照fabric1.4网络搭建的流程来解读每一步遇到的配置,欢迎搭建提出问题以及建议。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值