HyperledgerBesu-Orion 配置私人交易网络和多租用户

前提条件

https://besu.hyperledger.org/en/stable/Tutorials/Private-Network/Create-IBFT-Network/


tip

本教程中的步骤将创建一个隔离但不受保护或安全的以太坊专用网络。我们建议在正确配置的防火墙后面运行专用网络。

本教程使用IBFT 2.0配置专用网络仅用于教育目的。IBFT 2.0要求4个验证器具有拜占庭容错能力。

创建步骤

第一步:创建目录

每个节点都需要一个用于区块链数据的数据目录。为专用网络,四个节点中的每个节点创建目录,并为每个节点创建一个数据目录

IBFT-Network/
├── Node-1
│   ├── data
├── Node-2
│   ├── data
├── Node-3
│   ├── data
└── Node-4
    ├── data

第二步:创建配置文件

alloc除测试外,请勿使用MainNet或任何公共网络上的创世纪文件中的帐户。显示私钥,这意味着帐户不安全。

{
 "genesis": {
   "config": {
      "chainId": 2018,
      "constantinoplefixblock": 0,
      "ibft2": {
        "blockperiodseconds": 2,
        "epochlength": 30000,
        "requesttimeoutseconds": 10
      }
    },
    "nonce": "0x0",
    "timestamp": "0x58ee40ba",
    "gasLimit": "0x47b760",
    "difficulty": "0x1",
    "mixHash": "0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365",
    "coinbase": "0x0000000000000000000000000000000000000000",
    "alloc": {
       "fe3b557e8fb62b89f4916b721be55ceb828dbd73": {
          "privateKey": "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63",
          "comment": "private key and this comment are ignored.  In a real chain, the private key should NOT be stored",
          "balance": "0xad78ebc5ac6200000"
       },
       "627306090abaB3A6e1400e9345bC60c78a8BEf57": {
         "privateKey": "c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3",
         "comment": "private key and this comment are ignored.  In a real chain, the private key should NOT be stored",
         "balance": "90000000000000000000000"
       },
       "f17f52151EbEF6C7334FAD080c5704D77216b732": {
         "privateKey": "ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f",
         "comment": "private key and this comment are ignored.  In a real chain, the private key should NOT be stored",
         "balance": "90000000000000000000000"
       }
      }
 },
 "blockchain": {
   "nodes": {
     "generate": true,
       "count": 4
   }
 }
}

字段含义参考

第三步:生成节点密钥和创始文件

besu operator generate-blockchain-config --config-file=ibftConfigFile.json --to=networkFiles --private-key-file-name=key

Besu在networkFiles目录中创建以下内容:

  • genesis.json-包含extraData指定四个节点的属性的创世纪文件为验证者
  • 使用节点地址命名的每个节点的目录,其中包含每个节点的公钥和私钥
├── genesis.json
├── ibftConfigFile.json
└── networkFiles
    ├── genesis.json
    └── keys
        ├── 0x140150df1e4f9918baf704ab2a82a7de7dc6d574
        │   ├── key
        │   └── key.pub
        ├── 0xa858304ce109b26f8d680588ee539724a0b426f3
        │   ├── key
        │   └── key.pub
        ├── 0xdca6d858f0e07e8bb7ca48a86aff3cbb30235bf0
        │   ├── key
        │   └── key.pub
        └── 0xe2e0f9fb29e35cf855e8155a4f0d0d9b8d0c30fb
            ├── key
            └── key.pub

第四步:将创世纪文件复制到IBFT-Network目录

genesis.json文件复制到IBFT-Network目录

第五步:将节点私钥复制到节点目录

对于每个节点,将密钥文件复制到该data节点的目录中

IBFT-Network/
├── genesis.json
├── Node-1
│   ├── data
│   │    ├── key
│   │    ├── key.pub
├── Node-2
│   ├── data
│   │    ├── key
│   │    ├── key.pub
├── Node-3
│   ├── data
│   │    ├── key
│   │    ├── key.pub
├── Node-4
│   ├── data
│   │    ├── key
│   │    ├── key.pub

启动节点

Node-1

启动命令

节点启动时,将显示enode URL。在以下步骤中,复制enode URL以将Node-1指定为引导节点

besu --data-path=data --genesis-file=../genesis.json --rpc-http-enabled --rpc-http-api=ETH,NET,IBFT --host-whitelist="*" --rpc-http-cors-origins="all"

命令行:

  • 使用该--data-path选项指定Node-1的数据目录
  • 使用--rpc-http-enabled选项启用JSON-RPC API
  • 使用--rpc-http-api选项启用ETH,NET和IBFT API
  • 使用--host-whitelist选项启用对HTTP JSON-RPC API的所有主机访问
  • 使用--rpc-http-cors-origins选项通过HTTP JSON-RPC API启用对节点的全域访问

取出Enode URL

enode://fa3eecc56f6c721915506e902adcb392d254e33e7b246fe0381f9662ffbd136a675625a2649cfec383da52d8945a9a3e23c164fd979f532d9c0ad9ff82613b34@127.0.0.1:30303

启动 Node-2

注意p2p 端口和 http端口

besu --data-path=data --genesis-file=../genesis.json --bootnodes=enode://fa3eecc56f6c721915506e902adcb392d254e33e7b246fe0381f9662ffbd136a675625a2649cfec383da52d8945a9a3e23c164fd979f532d9c0ad9ff82613b34@127.0.0.1:30303 --p2p-port=30304 --rpc-http-enabled --rpc-http-api=ETH,NET,IBFT --host-whitelist="*" --rpc-http-cors-origins="all" --rpc-http-port=8546

命令行指定:

  • 使用该--data-path选项的Node-2的数据目录 。
  • 使用该--p2p-port选项,可以将节点1的不同端口用于P2P对等点发现 。
  • 使用该--rpc-http-port选项,可以将节点1的不同端口用于HTTP JSON-RPC 。
  • 使用该--bootnodes选项的Node-1的enode URL 。
  • 其他选项参考 Node-1 的。

启动 Node-3

besu --data-path=data --genesis-file=../genesis.json --bootnodes=enode://fa3eecc56f6c721915506e902adcb392d254e33e7b246fe0381f9662ffbd136a675625a2649cfec383da52d8945a9a3e23c164fd979f532d9c0ad9ff82613b34@127.0.0.1:30303 --p2p-port=30305 --rpc-http-enabled --rpc-http-api=ETH,NET,IBFT --host-whitelist="*" --rpc-http-cors-origins="all" --rpc-http-port=8547

命令行指定:

  • 使用该--data-path选项的Node-3的数据目录 。
  • 使用该--p2p-port选项,节点1和节点2的端口不同,用于P2P对等点发现 。
  • 使用该--rpc-http-port选项,HTTP JSON-RPC的节点1和节点2的端口不同 。
  • 引导节点与Node-2相同。

启动Node-4

besu --data-path=data --genesis-file=../genesis.json --bootnodes=enode://fa3eecc56f6c721915506e902adcb392d254e33e7b246fe0381f9662ffbd136a675625a2649cfec383da52d8945a9a3e23c164fd979f532d9c0ad9ff82613b34@127.0.0.1:30303 --p2p-port=30306 --rpc-http-enabled --rpc-http-api=ETH,NET,IBFT --host-whitelist="*" --rpc-http-cors-origins="all" --rpc-http-port=8548

命令行指定:

  • 使用该--data-path选项的Node-4的数据目录 。
  • 使用该--p2p-port选项,节点1,节点2和节点3的端口不同,用于P2P对等点发现 。
  • 使用该--rpc-http-port选项,HTTP JSON-RPC的节点1,节点2和节点3的端口不同 。
  • 引导节点与Node-2相同。

使用 api 确认专用网络正在运行

Node-1

curl -X POST --data '{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id":1}' localhost:8545
  • 结果确认Node-1具有三个对等节点(Node-2,Node-3和Node-4)
{
  "jsonrpc" : "2.0",
  "id" : 1,
  "result" : "0x3"
}

Node-1

curl -X POST --data '{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id":1}' localhost:8546

列出在指定块中定义的验证器

curl -X POST --data '{"jsonrpc":"2.0","method":"ibft_getValidatorsByBlockNumber","params":["latest"], "id":1}' http://127.0.0.1:8545

添加验证器节点

curl -X POST --data '{"jsonrpc":"2.0","method":"ibft_proposeValidatorVote","params":["42d4287eac8078828cf5f3486cfe601a275a49a5",true], "id":1}' http://127.0.0.1:8545

为私人交易配置网络

可以停止上述节点,在后续使用时再开启

https://besu.hyperledger.org/en/stable/Tutorials/Privacy/Configuring-Privacy/

第一步:创建Orion目录

在每个Node-*目录中,创建一个Orion目录

IBFT-Network/
├── Node-1
│   ├── data
│   ├── Orion
├── Node-2
│   ├── data
│   ├── Orion
└── Node-3
    ├── data
    ├── Orion

第二步:创建密码文件

在每个Orion目录中,创建一个名为的文件,passwordFile其中包含用于加密每个Orion密钥对的密码。

第三步:生成Orion密钥

在每个Orion目录中,为Orion节点生成一个公共/私有密钥对:

orion -g nodeKey

在提示符下,输入passwordFile中保存的密码以加密密钥对。

Orion会生成公用/专用密钥对,并将密钥保存在nodeKey.pub和 nodeKey.key文件中

第四步:创建Orion配置文件

Node-1/Orion目录中,创建一个名为的文件,orion.conf并添加以下属性:

nodeurl = "http://127.0.0.1:8080/"
nodeport = 8080
clienturl = "http://127.0.0.1:8888/"
clientport = 8888
publickeys = ["nodeKey.pub"]
privatekeys = ["nodeKey.key"]
passwords = "passwordFile"
tls = "off"

Node-2/OrionNode-3/Orion目录中,创建orion.conf指定以下内容的文件:

  • 不同的端口
  • 作为引导节点的Node-1 Orion节点,(由指定 othernodes)。
nodeurl = "http://127.0.0.1:8081/"
nodeport = 8081
clienturl = "http://127.0.0.1:8889/"
clientport = 8889
publickeys = ["nodeKey.pub"]
privatekeys = ["nodeKey.key"]
passwords = "passwordFile"
othernodes = ["http://127.0.0.1:8080/"]
tls = "off"
nodeurl = "http://127.0.0.1:8082/"
nodeport = 8082
clienturl = "http://127.0.0.1:8890/"
clientport = 8890
publickeys = ["nodeKey.pub"]
privatekeys = ["nodeKey.key"]
passwords = "passwordFile"
othernodes = ["http://127.0.0.1:8080/"]
tls = "off"

第五步:启动Orion节点

在每个Orion目录中,启动Orion并指定在上一步中创建的 配置文件

orion orion.conf

第六步:启动Besu

Node-1

besu --data-path=data --genesis-file=../genesis.json --rpc-http-enabled --rpc-http-api=ETH,NET,IBFT,EEA,PRIV --host-whitelist="*" --rpc-http-cors-origins="all" --privacy-enabled --privacy-url=http://127.0.0.1:8888 --privacy-public-key-file=Orion/nodeKey.pub --min-gas-price=0

命令行指定隐私选项:

  • --privacy-enabled 启用隐私
  • --privacy-url指定Orion节点的URL(clienturl在中orion.conf)
  • --privacy-public-key-file 指定包含Orion节点公钥的文件(在3. Generate Orion Keys中创建 )
  • --rpc-http-api在JSON-RPC API列表中包含EEA和PRIV,以启用隐私JSON-RPC API方法。
  • --min-gas-price自由气体网络的值为0 。

节点启动时,将显示enode URL。在以下步骤中,复制enode URL以将Node-1指定为引导节点。

启动Besu Node-2

在Node-2目录中,启动Besu Node-2,指定在启动Node-1作为引导节点时复制的Node-1 enode URL:

命令行指定与Node-1相同的选项,但端口和Orion节点URL不同。该--bootnodes选项指定节点1的enode URL。

besu --data-path=data --genesis-file=../genesis.json --bootnodes=enode://fa3eecc56f6c721915506e902adcb392d254e33e7b246fe0381f9662ffbd136a675625a2649cfec383da52d8945a9a3e23c164fd979f532d9c0ad9ff82613b34@127.0.0.1:30303 --p2p-port=30304 --rpc-http-enabled --rpc-http-api=ETH,NET,IBFT,EEA,PRIV --host-whitelist="*" --rpc-http-cors-origins="all" --rpc-http-port=8546 --privacy-enabled --privacy-url=http://127.0.0.1:8889 --privacy-public-key-file=Orion/nodeKey.pub --min-gas-price=0

启动Besu Node-3

命令行指定与Node-1相同的选项,但端口和Orion节点URL不同。该--bootnodes选项指定节点1的enode URL。

besu --data-path=data --genesis-file=../genesis.json --bootnodes=enode://fa3eecc56f6c721915506e902adcb392d254e33e7b246fe0381f9662ffbd136a675625a2649cfec383da52d8945a9a3e23c164fd979f532d9c0ad9ff82613b34@127.0.0.1:30303 --p2p-port=30305 --rpc-http-enabled --rpc-http-api=ETH,NET,IBFT,EEA,PRIV --host-whitelist="*" --rpc-http-cors-origins="all" --rpc-http-port=8547 --privacy-enabled --privacy-url=http://127.0.0.1:8890 --privacy-public-key-file=Orion/nodeKey.pub --min-gas-price=0

配置多租户网络

<font color=red>可以停止上述节点。</font>

可以在启用了隐私的网络中将Besu和关联的Orion节点配置为托管 多个租户。

将Node-1在启用了隐私的网络中将租户添加到Besu和Orion节点 。此例使用JSON Web令牌(JWT)公共密钥身份验证来创建租户的JWT,但是您也可以使用用户名和密码身份验证。

IBFT-Network/
├── Node-1
│   ├── data
│   ├── Orion
├── Node-2
│   ├── data
│   ├── Orion
└── Node-3
    ├── data
    ├── Orion

第一步:生成私钥和公钥对

openssl genrsa -out privateKey.pem 2048
openssl rsa -pubout -in privateKey.pem -pubout -out publicKey.pem
image.png

上面两个文件在创建JWT时有用到。

image.png

第二步:生成Orion密钥

Node-1/Orion目录中, 为每个租户生成一个公钥/私钥对。

orion -g nodeKey2

密码:user2


orion -g nodeKey3

密码:user3


租户公钥文件明示

其中,nodeKey2.pubnodeKey3.pub,在JWT时用到。

第三步:更新密码文件

即使每个密码对都相同,您也需要单独的密码。

image.png

第四步:更新Orion配置文件

在Node-1/Orion目录中,orion.conf通过添加新的密钥对来更新文件:

nodeurl = "http://127.0.0.1:8080/"
nodeport = 8080
clienturl = "http://127.0.0.1:8888/"
clientport = 8888
publickeys = ["nodeKey.pub", "nodeKey2.pub", "nodeKey3.pub"]
privatekeys = ["nodeKey.key", "nodeKey2.key", "nodeKey3.key"]
passwords = "passwordFile"
tls = "off"

第五步:启动Orion节点

每个Orion目录中,启动Orion并指定配置文件。

orion orion.conf

第六步:启动

启动Besu Node-1,开启认证

besu --data-path=data --genesis-file=../genesis.json --rpc-http-authentication-enabled --rpc-http-authentication-jwt-public-key-file=publicKey.pem --rpc-http-enabled --rpc-http-api=ETH,NET,IBFT,EEA,PRIV --host-whitelist="*" --rpc-http-cors-origins="all" --privacy-enabled --privacy-url=http://127.0.0.1:8888 --privacy-multi-tenancy-enabled --min-gas-price=0

命令行指定隐私选项:

  • --rpc-http-authentication-enabled 启用JSON-RPC API的身份验证。
    ---rpc-http-authentication-jwt-public-key-file 指定操作员的公钥文件。用于对租户JWT进行身份验证。
  • --privacy-enabled 启用隐私。
  • --privacy-url指定Orion节点的URL(clienturl在中orion.conf)
  • --privacy-multi-tenancy-enabled 启用多租户。

启动其他节点

参照前面的启动命令

第七步:生成租户JWT

为每个租户生成JWT,并在 字段中指定租户的Orion公钥privacyPublicKey。

请参考官网

参考

image.png

确保将适当的 JSON-RPC API权限应用于令牌。例如,确保您启用PRIV和EEAAPI以保护隐私

{
  "alg": "RS256",
  "typ": "JWT"
}

字段含义:

  • alg:算法名
  • typ:算法类型

{
  "permissions": [
    "*:*"
  ],
  "exp": 1607506515,
  "privacyPublicKey": "7W+V5henfz7gIRjxOxL0MvXa4o1hN+YOeDhmkowOrxk="
}

字段含义:

image.png

https://jwt.io/#debugger-io?token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJwZXJtaXNzaW9ucyI6WyIqOioiXSwiZXhwIjoxNjA3NTA2NTE1LCJwcml2YWN5UHVibGlja2V5IjoiWnlCQUYrMHFlbWFtMXZpNldFWW5HeXlPNjdzd1FmVCtLZXI1eDlnZ1lpQT0ifQ.SHvSZyiZJdS_hooG9p-L6vx-STjVJhI9BkwU5o1pOVnYUVslBPSQH_TSedet2M5rOg9pb-7WPUy7QBulCjNJ7Qh7R7K2i0oBYez5pET3hdJC6yAkCFWX1IXiq1oUefJvsRzxf-6wd8HPbRi5ztJ-ovFnwPWiClB0mwhnFGryuPQXDlE1-Pdtaj4b7BeC5M7v1dMuYirXVDS5yXP3tUckmNKn96uBDBYLSF4bRfCqlCRekXvfJykG1iVkVmXlCqIUraqYUsHmxaf9VYhOIHpcihvQGESmcZ3GqCVqFD1gxg-kRT1yRjFGElFN95F10kuEy2CKJ-xEsRerOO0A9gNz2w&publicKey=-----BEGIN%20PUBLIC%20KEY-----%0AMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApe%2BfbkwctpGc%2FyABTGCx%0A4RlRLluqpOngjizx1zttqXVIqrhnVF0rcIz%2BvvbmBvBbmBZpyAZ57yb3u0CjBXtO%0AGGe6u8auZXAijEh7gAqh6Vxxvg%2Btum6stGPRx1x6F0iLbdT4W3ke%2BVg5rA2hVSNY%0A7832BLjKWZQG032n3qYEeG1vj1pkY38n385LASqJLjEFRB%2BmJvWw%2BsDvJopl830l%0AFuDOhsjgh23PKnEPm7FNBwTktReVqbWJmLLf3g1OO%2BZ0Ht2OUhVR%2Bzb11V2HJPYi%0AkDhbn4H6mToidRF%2BSAxd%2FENhX9eb7Tp%2BSdNrFN%2BQ4jqTwXr6zW13WCMlJohJzlOG%0AfQIDAQAB%0A-----END%20PUBLIC%20KEY-----

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwZXJtaXNzaW9ucyI6WyIqOioiXSwiZXhwIjoxNjA3NTA2NTE1LCJwcml2YWN5UHVibGlja2V5IjoiWnlCQUYrMHFlbWFtMXZpNldFWW5HeXlPNjdzd1FmVCtLZXI1eDlnZ1lpQT0ifQ.tMsk3x1bK8PIbgFKpi0G9CwxXjWltXk6DwGZf5-9IKk

使用身份验证令牌发出请求

  • Node-1 开启了认证,请求 Node-1 ,不带 Token,将无权访问

curl -X POST -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJwZXJtaXNzaW9ucyI6WyIqOioiXSwiZXhwIjoxNjA3NTA2NTE1LCJwcml2YWN5UHVibGlja2V5IjoiWnlCQUYrMHFlbWFtMXZpNldFWW5HeXlPNjdzd1FmVCtLZXI1eDlnZ1lpQT0ifQ.SHvSZyiZJdS_hooG9p-L6vx-STjVJhI9BkwU5o1pOVnYUVslBPSQH_TSedet2M5rOg9pb-7WPUy7QBulCjNJ7Qh7R7K2i0oBYez5pET3hdJC6yAkCFWX1IXiq1oUefJvsRzxf-6wd8HPbRi5ztJ-ovFnwPWiClB0mwhnFGryuPQXDlE1-Pdtaj4b7BeC5M7v1dMuYirXVDS5yXP3tUckmNKn96uBDBYLSF4bRfCqlCRekXvfJykG1iVkVmXlCqIUraqYUsHmxaf9VYhOIHpcihvQGESmcZ3GqCVqFD1gxg-kRT1yRjFGElFN95F10kuEy2CKJ-xEsRerOO0A9gNz2w' -d '{"jsonrpc":"2.0","method":"net_listening","params":[],"id":1}' http://localhost:8545

image.png

curl -X POST -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJwZXJtaXNzaW9ucyI6WyIqOioiXSwiZXhwIjoxNjA3NTA2NTE1LCJwcml2YWN5UHVibGlja2V5IjoiWnlCQUYrMHFlbWFtMXZpNldFWW5HeXlPNjdzd1FmVCtLZXI1eDlnZ1lpQT0ifQ.SHvSZyiZJdS_hooG9p-L6vx-STjVJhI9BkwU5o1pOVnYUVslBPSQH_TSedet2M5rOg9pb-7WPUy7QBulCjNJ7Qh7R7K2i0oBYez5pET3hdJC6yAkCFWX1IXiq1oUefJvsRzxf-6wd8HPbRi5ztJ-ovFnwPWiClB0mwhnFGryuPQXDlE1-Pdtaj4b7BeC5M7v1dMuYirXVDS5yXP3tUckmNKn96uBDBYLSF4bRfCqlCRekXvfJykG1iVkVmXlCqIUraqYUsHmxaf9VYhOIHpcihvQGESmcZ3GqCVqFD1gxg-kRT1yRjFGElFN95F10kuEy2CKJ-xEsRerOO0A9gNz2w' -d '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' http://localhost:8545

eth_gasPrice

curl -X POST -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJwZXJtaXNzaW9ucyI6WyIqOioiXSwiZXhwIjoxNjA3NTA2NTE1LCJwcml2YWN5UHVibGlja2V5IjoiWnlCQUYrMHFlbWFtMXZpNldFWW5HeXlPNjdzd1FmVCtLZXI1eDlnZ1lpQT0ifQ.SHvSZyiZJdS_hooG9p-L6vx-STjVJhI9BkwU5o1pOVnYUVslBPSQH_TSedet2M5rOg9pb-7WPUy7QBulCjNJ7Qh7R7K2i0oBYez5pET3hdJC6yAkCFWX1IXiq1oUefJvsRzxf-6wd8HPbRi5ztJ-ovFnwPWiClB0mwhnFGryuPQXDlE1-Pdtaj4b7BeC5M7v1dMuYirXVDS5yXP3tUckmNKn96uBDBYLSF4bRfCqlCRekXvfJykG1iVkVmXlCqIUraqYUsHmxaf9VYhOIHpcihvQGESmcZ3GqCVqFD1gxg-kRT1yRjFGElFN95F10kuEy2CKJ-xEsRerOO0A9gNz2w' -d '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":1}' http://localhost:8545

curl -X POST -d '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":1}' http://localhost:8545

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值