【以太坊】Debugging Ethereum-cpp

# Source

$git clone --recursive https://github.com/ethereum/cpp-ethereum

Depends

$ cd cpp-ethereum 
$ sh scripts/install_deps.sh

Build

NOTE: remove GUI, MINIUPNPC, VMJIT, TESTS etc. from CMakeLists.txt, to accelerate building:

$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Debug ../

or configure as following:

cmake -DEVMJIT=Off -DTESTS=Off -DETHASHCL=Off -DMINIUPNPC=Off -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=`pwd`/../bin ..
-- The C compiler identification is GNU 5.2.1
-- The CXX compiler identification is GNU 5.2.1
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done

------------------------------------------------------------------------
-- Configuring cpp-ethereum
------------------------------------------------------------------------
--                  CMake Version                            3.2.2
-- CMAKE_BUILD_TYPE Build type                               Debug
-- TARGET_PLATFORM  Target platform                          Linux
--------------------------------------------------------------- features
--                  Hardware identification support          
--                  HTTP Request support                     
-- VMTRACE          VM execution tracing                     OFF
-- PROFILING        Profiling support                        OFF
-- FATDB            Full database exploring                  ON
-- ROCKSDB          Prefer rocksdb to leveldb                OFF
-- OLYMPIC          Default to the Olympic network           OFF
-- PARANOID         -                                        OFF
------------------------------------------------------------- components
-- ETHASHCL         Build OpenCL components                  ON
-- SOLIDITY         Build Solidity                           ON
------------------------------------------------------------------------

-- Found jsoncpp: /usr/lib/x86_64-linux-gnu/libjsoncpp.so  
-- JsonCpp headers: /usr/include/jsoncpp
-- JsonCpp lib   : /usr/lib/x86_64-linux-gnu/libjsoncpp.so
-- Found json_rpc_cpp: /usr/local/include (found suitable version "0.6.0", minimum required is "0.4") 
-- json-rpc-cpp headers: /usr/local/include
-- json-rpc-cpp lib   : /usr/local/lib/libjsonrpccpp-common.so;/usr/local/lib/libjsonrpccpp-server.so;/usr/local/lib/libjsonrpccpp-client.so
-- Found CURL: /usr/lib/x86_64-linux-gnu/libcurl.so  
-- curl headers: /usr/include
-- curl lib   : /usr/lib/x86_64-linux-gnu/libcurl.so
-- Found leveldb: /usr/lib/x86_64-linux-gnu/libleveldb.so  
-- Found CryptoPP: /usr/include (found suitable version "5.6.2", minimum required is "5.6.2") 
-- CryptoPP headers: /usr/include
-- CryptoPP lib   : /usr/lib/libcryptopp.so
-- Cpuid headers: CPUID_INCLUDE_DIR-NOTFOUND
-- Cpuid lib   : CPUID_LIBRARY-NOTFOUND
-- Looking for CL_VERSION_2_0
-- Looking for CL_VERSION_2_0 - found
-- Found OpenCL: /usr/lib/x86_64-linux-gnu/libOpenCL.so.1 (found version "2.0") 
-- OpenCL headers: /usr/include
-- OpenCL lib   : /usr/lib/x86_64-linux-gnu/libOpenCL.so.1
-- Found miniupnpc: /usr/lib/x86_64-linux-gnu/libminiupnpc.so  
-- miniupnpc headers: /usr/include
-- miniupnpc lib   : /usr/lib/x86_64-linux-gnu/libminiupnpc.so
-- Found mhd: /usr/lib/x86_64-linux-gnu/libmicrohttpd.so  
-- microhttpd headers: /usr/include
-- microhttpd lib   : /usr/lib/x86_64-linux-gnu/libmicrohttpd.so
-- jsonrpcstub location    : /usr/local/bin/jsonrpcstub
-- test: ClientBase |  --eth_testfile=BlockTests/bcJS_API_Test --eth_threads=1; --eth_testfile=BlockTests/bcJS_API_Test --eth_threads=3; --eth_testfile=BlockTests/bcJS_API_Test --eth_threads=10; --eth_testfile=BlockTests/bcValidBlockTest --eth_threads=1; --eth_testfile=BlockTests/bcValidBlockTest --eth_threads=3; --eth_testfile=BlockTests/bcValidBlockTest --eth_threads=10
-- test: JsonRpc |  --eth_testfile=BlockTests/bcJS_API_Test; --eth_testfile=BlockTests/bcValidBlockTest
-- Found gmp: /usr/lib/x86_64-linux-gnu/libgmp.so  
-- Gmp headers: /usr/include/x86_64-linux-gnu
-- Gmp lib   : /usr/lib/x86_64-linux-gnu/libgmp.so
-- Configuring done
-- Generating done
-- Build files have been written to: /root/workspace/github/cpp-ethereum/build

$ make

Scanning dependencies of target cpp-ethereum_BuildInfo.h
[  0%] Built target cpp-ethereum_BuildInfo.h
Scanning dependencies of target secp256k1
[  0%] Building C object utils/secp256k1/CMakeFiles/secp256k1.dir/secp256k1.c.o
Linking C static library libsecp256k1.a
[  0%] Built target secp256k1
Scanning dependencies of target devcore
...
[ 36%] Building CXX object libp2p/CMakeFiles/p2p.dir/Common.cpp.o
Linking CXX shared library libp2p.so
[ 36%] Built target p2p
Scanning dependencies of target ethereum
[ 36%] Building CXX object libethereum/CMakeFiles/ethereum.dir/ClientTest.cpp.o
[ 37%] Building CXX object libethereum/CMakeFiles/ethereum.dir/Utility.cpp.o
[ 37%] Building CXX object libethereum/CMakeFiles/ethereum.dir/GasPricer.cpp.o
[ 38%] Building CXX object libethereum/CMakeFiles/ethereum.dir/Account.cpp.o
[ 38%] Building CXX object libethereum/CMakeFiles/ethereum.dir/CachedAddressState.cpp.o
[ 39%] Building CXX object libethereum/CMakeFiles/ethereum.dir/LogFilter.cpp.o
[ 39%] Building CXX object libethereum/CMakeFiles/ethereum.dir/Client.cpp.o

...

[ 95%] Building CXX object test/libweb3core/test/CMakeFiles/testweb3core.dir/libp2p/rlpx.cpp.o
[ 95%] Building CXX object test/libweb3core/test/CMakeFiles/testweb3core.dir/libp2p/eip-8.cpp.o
[ 96%] Building CXX object test/libweb3core/test/CMakeFiles/testweb3core.dir/libp2p/capability.cpp.o
Linking CXX executable testweb3core
[ 96%] Built target testweb3core
Scanning dependencies of target testweb3
[ 97%] Building CXX object test/webthree/test/CMakeFiles/testweb3.dir/test.cpp.o
[ 97%] Building CXX object test/webthree/test/CMakeFiles/testweb3.dir/libwhisper/shhrpc.cpp.o
[ 98%] Building CXX object test/webthree/test/CMakeFiles/testweb3.dir/libwhisper/whisperMessage.cpp.o
[ 98%] Building CXX object test/webthree/test/CMakeFiles/testweb3.dir/libwhisper/whisperTopic.cpp.o
[ 99%] Building CXX object test/webthree/test/CMakeFiles/testweb3.dir/libwhisper/bloomFilter.cpp.o
[ 99%] Building CXX object test/webthree/test/CMakeFiles/testweb3.dir/libwhisper/whisperDB.cpp.o
[100%] Building CXX object test/webthree/test/CMakeFiles/testweb3.dir/libweb3jsonrpc/Client.cpp.o
[100%] Building CXX object test/webthree/test/CMakeFiles/testweb3.dir/libweb3jsonrpc/AccountHolder.cpp.o
[100%] Building CXX object test/webthree/test/CMakeFiles/testweb3.dir/libweb3jsonrpc/jsonrpc.cpp.o
Linking CXX executable testweb3
[100%] Built target testweb3

Install

Note: default install into /usr/local/bin

$ make install
$ cd /usr/local/bin
$ ls
bench  eth  ethkey  ethminer  ethvm  jsonrpcstub  lllc  rlp  solc

Debugging

$ gdb --args ./eth --help

Note: not all help entries are displayed(bug?)

Usage eth [OPTIONS]
Options:

Wallet usage:
    account list  List all keys available in wallet.
    account new Create a new key and add it to the wallet.
    account update [<uuid>|<address> , ... ]  Decrypt and re-encrypt given keys.
    account import [<uuid>|<file>|<secret-hex>] Import keys from given source and place in wallet.
    wallet import <file>    Import a presale wallet.

Client mode (default):
    --olympic  Use the Olympic (0.9) protocol.
    --frontier  Use the Frontier (1.0) protocol.
    --morden  Use the Morden testnet.
    --private <name>  Use a private chain.
    --test  Testing mode: Disable PoW and provide test rpc interface.
    --config <file>  Configure specialised blockchain using given JSON information.
    --oppose-dao-fork  Ignore DAO hard fork (default is to participate).

    -o,--mode <full/peer>  Start a full node or a peer node (default: full).

    -j,--json-rpc  Enable JSON-RPC server (default: off).
    --ipc  Enable IPC server (default: on).
    --ipcpath Set .ipc socket path (default: data directory)
    --admin-via-http  Expose admin interface via http - UNSAFE! (default: off).
    --no-ipc  Disable IPC server.
    --json-rpc-port <n>  Specify JSON-RPC server port (implies '-j', default: 8545).
    --rpccorsdomain <domain>  Domain on which to send Access-Control-Allow-Origin header.
    --admin <password>  Specify admin session key for JSON-RPC (default: auto-generated and printed at start-up).
    -K,--kill  Kill the blockchain first.
    -R,--rebuild  Rebuild the blockchain from the existing database.
    --rescue  Attempt to rescue a corrupt database.

    --import-presale <file>  Import a pre-sale key; you ll need to specify the password to this key.
    -s,--import-secret <secret>  Import a secret key into the key store and use as the default.
    -S,--import-session-secret <secret>  Import a secret key into the key store and use as the default for this session only.
    --sign-key <address>  Sign all transactions with the key of the given address.
    --session-sign-key <address>  Sign all transactions with the key of the given address for this session only.
    --master <password>  Give the master password for the key store. Use --master "" to show a prompt.
    --password <password>  Give a password for a private key.

Client transacting:
    --ask <wei>  Set the minimum ask gas price under which no transaction will be mined (default 20000000000 ).
    --bid <wei>  Set the bid gas price to pay for transactions (default 20000000000 ).
    --unsafe-transactions  Allow all transactions to proceed without verification. EXTREMELY UNSAFE.
Client mining:
    -a,--address <addr>  Set the author (mining payout) address to given address (default: auto).
    -m,--mining <on/off/number>  Enable mining, optionally for a specified number of blocks (default: off).
    -f,--force-mining  Mine even when there are no transactions to mine (default: off).
    -C,--cpu  When mining, use the CPU.
    -G,--opencl  When mining, use the GPU via OpenCL.
    --opencl-platform <n>  When mining using -G/--opencl, use OpenCL platform n (default: 0).
    --opencl-device <n>  When mining using -G/--opencl, use OpenCL device n (default: 0).
    -t, --mining-threads <n>  Limit number of CPU/GPU miners to n (default: use everything available on selected platform).

Client networking:
    --client-name <name>  Add a name to your client s version string (default: blank).
    --bootstrap  Connect to the default Ethereum peer servers (default unless --no-discovery used).
    --no-bootstrap  Do not connect to the default Ethereum peer servers (default only when --no-discovery is used).
    -x,--peers <number>  Attempt to connect to a given number of peers (default: 11).
    --peer-stretch <number>  Give the accepted connection multiplier (default: 7).
    --public-ip <ip>  Force advertised public IP to the given IP (default: auto).
    --listen-ip <ip>(:<port>)  Listen on the given IP for incoming connections (default: 0.0.0.0).
    --listen <port>  Listen on the given port for incoming connections (default: 30303).
    -r,--remote <host>(:<port>)  Connect to the given remote host (default: none).
    --port <port>  Connect to the given remote port (default: 30303).
    --network-id <n>  Only connect to other hosts with this network id.
    --upnp <on/off>  Use UPnP for NAT (default: on).
    --peerset <list>  Space delimited list of peers; element format: type:publickey@ipAddress[:port].
        Types:
        default     Attempt connection when no other peers are available and pinning is disabled.
        required        Keep connected at all times.
    --no-discovery  Disable node discovery, implies --no-bootstrap.
    --pin  Only accept or connect to trusted peers.
    --hermit  Equivalent to --no-discovery --pin.
    --sociable  Force discovery and no pinning.

Work farming mode:
    -F,--farm <url>  Put into mining farm mode with the work server at URL (default: http://127.0.0.1:8545)
    --farm-recheck <n>  Leave n ms between checks for changed work (default: 500).
    --no-precompute  Don t precompute the next epoch s DAG.
Ethash verify mode:
    -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce>  Check PoW credentials for validity.

Benchmarking mode:
    -M,--benchmark  Benchmark for mining and exit; use with --cpu and --opencl.
    --benchmark-warmup <seconds>  Set the duration of warmup for the benchmark tests (default: 3).
    --benchmark-trial <seconds>  Set the duration for each trial for the benchmark tests (default: 3).
    --benchmark-trials <n>  Set the number of trials for the benchmark tests (default: 5).
    --phone-home <on/off>  When benchmarking, publish results (default: on)
DAG creation mode:
    -D,--create-dag <number>  Create the DAG in preparation for mining on given block and exit.
Mining configuration:
    -C,--cpu  When mining, use the CPU.
    -G,--opencl  When mining use the GPU via OpenCL.
    --opencl-platform <n>  When mining using -G/--opencl use OpenCL platform n (default: 0).
    --opencl-device <n>  When mining using -G/--opencl use OpenCL device n (default: 0).
    -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)
    --allow-opencl-cpu Allows CPU to be considered as an OpenCL device if the OpenCL platform supports it.
    --list-devices List the detected OpenCL devices and exit.
    --current-block Let the miner know the current block number at configuration time. Will help determine DAG size and required GPU memory.
    --disable-submit-hashrate  When mining, don t submit hashrate to node.
    --cl-extragpu-mem Set the memory (in MB) you believe your GPU requires for stuff other than mining. Windows rendering e.t.c..
    --cl-local-work Set the OpenCL local work size. Default is 64
    --cl-global-work Set the OpenCL global work size as a multiple of the local work size. Default is 4096 * 64
    --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is 0. If 0 is given then no autoadjustment of global work size will happen
Import/export modes:
    --from <n>  Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'.
    --to <n>  Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'.
    --only <n>  Equivalent to --export-from n --export-to n.
    --dont-check  Prevent checking some block aspects. Faster importing, but to apply only when the data is known to be valid.

General Options:
    -d,--db-path,--datadir <path>  Load database from path (default: /root/.ethereum).
    -v,--verbosity <0 - 9>  Set the log verbosity from 0 to 9 (default: 8).
    -V,--version  Show the version and exit.
    -h,--help  Show this help message and exit.

Experimental / Proof of Concept:
    --shh  Enable Whisper.

Wallet

  • Create wallet
$ cd build/ethkey
$ ./ethkey createwallet
Please enter a MASTER passphrase to protect your key store (make it strong!): 
Please confirm the passphrase by entering it again: 
  • Create key
./ethkey new testkey0
Please enter your MASTER passphrase: 
Enter a passphrase with which to secure this account (or nothing to use the master passphrase): 
Please confirm the passphrase by entering it again: 
Created key a2e93a4d-1e68-e723-a677-7448be540d95
  Name: testkey0
  Password hint: 
  ICAP: XE2113T1643JT73UYHLYN4FH8V5CRZS0KJ
  Raw hex: 00435055f6e288a801aa7415a21690c535ff40e3
  • List keys
$ ./ethkey list
Please enter your MASTER passphrase: 
764c1f9e-e806-dbd4-ac0f-8856050e3395 00c56f8b… XE1038R6CAKY4CFOPAODNNHGSOSKP1IP7P  
a1b56307-50c3-7e0e-7e09-9928332fa0a7 000120ed… XE5900O0YWPKSTYTWDZBLS66VKLAY515P6 
  • Or list keys by: eth account list
$ build/eth/eth account list
...  11:25:13.389|eth  Reading /root/.web3/keys/a1b56307-50c3-7e0e-7e09-9928332fa0a7.json
...  11:25:13.390|eth  Reading /root/.web3/keys/764c1f9e-e806-dbd4-ac0f-8856050e3395.json
Please enter your MASTER passphrase: 
Account #0: {00c56f8b9ac4e59be3b194d534ebe736d9c53525}
Account #1: {000120ed08b4d93b0242d31c18ed7e90e10ca01a}

DataDir

Default datadir is ~/.ethereum, and wallet, account options will ignore –datadir option.

Note: datadir may not work correctly. (bug?)

KeyId

$ ls -l ~/.web3/keys
-rw------- 1 root root 699  92 11:20 764c1f9e-e806-dbd4-ac0f-8856050e3395.json
-rw------- 1 root root 699  92 11:20 a1b56307-50c3-7e0e-7e09-9928332fa0a7.json
$ cat 764c1f9e-e806-dbd4-ac0f-8856050e3395.json
{
    "address" : "00c56f8b9ac4e59be3b194d534ebe736d9c53525",
    "crypto" : {
        "cipher" : "aes-128-ctr",
        "cipherparams" : {
            "iv" : "670d27f6652969655c04fe533d8eb864"
        },
        "ciphertext" : "d39907d8901a7c582afeeac0e9dc1a2a5c83c61a5f5ba0525d813640d9a34508",
        "kdf" : "scrypt",
        "kdfparams" : {
            "dklen" : 32,
            "n" : 262144,
            "p" : 1,
            "r" : 8,
            "salt" : "3f48c6759cb2b15dc7c9a52c346e710cc88a41ebf0a9f1cd456df005992ac309"
        },
        "mac" : "f95b7713470decba82370292bfc19d1bd3d51b458aa914508542290281b86452"
    },
    "id" : "764c1f9e-e806-dbd4-ac0f-8856050e3395",
    "version" : 3
}

Note: see the address field in json

bool AccountManager::openWallet() will prompt for master key passphrase

226 bool AccountManager::openWallet()
227 {
228     if (!m_keyManager)
229     {
230         m_keyManager.reset(new KeyManager());
231         if (m_keyManager->exists())
232         {
233             if (m_keyManager->load(std::string()) || m_keyManager->load(getPassword("Please enter your MASTER passphrase: ")))
234                 return true;
235             else

Genesis

The default frontier genesis info

cpp-ethereum/libethereum/ChainParams.cpp:55

dev::eth::ChainParams::loadConfig (this=0x7fffffffc710, _json=..., _stateRoot=...)

dump binary memory

(gdb) p /x _json

$10 = (const std::__cxx11::string &) @0x7ffff722c440: {static npos = 0xffffffffffffffff, 
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fffeaaba010}, 
  _M_string_length = 0xc757d, {_M_local_buf = {0x0, 0xd9, 0x11, 0x0 <repeats 13 times>}, _M_allocated_capacity = 0x11d900}}

(gdb) dump binary memory result.txt 0x7fffeaaba010 0x7fffeaaba010+816509

$ cat result.txt

{
    "sealEngine": "Ethash",
    "params": {
        "accountStartNonce": "0x00",
        "frontierCompatibilityModeLimit": "0x118c30",
        "daoHardforkBlock": "0x1d4c00",
        "maximumExtraDataSize": "0x20",
        "tieBreakingGas": false,
        "minGasLimit": "0x1388",
        "maxGasLimit": "7fffffffffffffff",
        "gasLimitBoundDivisor": "0x0400",
        "minimumDifficulty": "0x020000",
        "difficultyBoundDivisor": "0x0800",
        "durationLimit": "0x0d",
        "blockReward": "0x4563918244F40000",
        "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
        "networkID" : "0x1"
    },
    "genesis": {
        "nonce": "0x0000000000000042",
        "difficulty": "0x400000000",
        "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "author": "0x0000000000000000000000000000000000000000",
        "timestamp": "0x00",
        "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
        "gasLimit": "0x1388"
    },
    "accounts": {
        "0000000000000000000000000000000000000001": { "precompiled": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
        "0000000000000000000000000000000000000002": { "precompiled": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
        "0000000000000000000000000000000000000003": { "precompiled": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
        "0000000000000000000000000000000000000004": { "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
        "3282791d6fd713f1e94f4bfd565eaa78b3a0599d": {
            "balance": "1337000000000000000000"
        }
........
}

Console

Interacting with your node can be done using either geth or the ethereum console:

Note:

$ npm install -g ethereum-console web3 repl process

$ ethconsole

Fixed: main.js

repl.start('>');

Usage:

$ ethconsole [javascript file] [ipc socket]

Connects to an ethereum node via ipc in order to control it remotely, through global variable web3 (web3.admin is also present). If no arguments are given, connects to the default ipc socket and drops into interactive mode.

Arguments:

  • ipc socket
    connect to the given ipc socket (use ipc:// if it does not end with .ipc)

  • javascript file
    execute the given javascript file that has to end in .js non-interactively. The script has to call process.exit() in order to terminate the console.

Web3 Console API Callback

Issue

>web3.eth.hashrate
Error: You tried to send "eth_hashrate" synchronously. Synchronous requests are not supported by the IPC provider.
    at IpcProvider.send (/usr/local/lib/node_modules/ethereum-console/node_modules/web3/lib/web3/ipcprovider.js:192:15)
    at RequestManager.send (/usr/local/lib/node_modules/ethereum-console/node_modules/web3/lib/web3/requestmanager.js:58:32)
    at Eth.get [as hashrate] (/usr/local/lib/node_modules/ethereum-console/node_modules/web3/lib/web3/property.js:107:62)
    at repl:1:10
    at REPLServer.self.eval (repl.js:112:21)
    at Interface.<anonymous> (repl.js:239:12)
    at Interface.EventEmitter.emit (events.js:95:17)
    at Interface._onLine (readline.js:202:10)
    at Interface._line (readline.js:531:8)
    at Interface._ttyWrite (readline.js:760:14)
>web3.eth.getMining(console.log);
undefined
>null false

PrivateChain

Section.1.5.3

$ ./ethkey –wallet-path pwd /dat createwallet

$ ./ethkey –wallet-path pwd/dat list

$ ./ethkey –wallet-path pwd/dat new testkey1

$ ./eth –datadir pwd/dat –genesis pwd/genesis.json –peers 0 –no-discovery -j –ipc

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值