当前位置:   article > 正文

Qtum量子链 跨链原子交换

Qtum量子链 跨链原子交换


摘要

回顾文章:Qtum研究院:Qtum企业版跨链交易解决方案——Canal


跨链是区块链面临的诸多难题之一,制约了区块链应用的发展。在所有的解决方案中,HTLC(Hash Time-Locked Contract)保证了跨链过程的原子性,安全性最高。本文提出了QTUM上的HTLC实现方案,并且进行了QTUM与BTC的一次跨链原子交换。

背景介绍

跨链原子交换[1],是跨链众多解决方案中的一种。这种方案的优点在于:

  1. 除了交易双方,不需要第三方参与,即交易双方不需要信任任何第三者。

  2. 交易过程具有原子性,即两种不同链上的两笔交易会一起完成或一起撤销。

方案的缺点在于:

  1. 需要交易撮合工具,让用户在交换之前对交换的数量进行协商。

  2. 交换时间受到区块链本身的交易确认时间的限制,会比中心化交易所慢。

跨链原子交换目前主要的应用是集成在多币种的钱包中,配合交易撮合工具,实现各个数字货币之间的转换。 底层的HTLC(hash time-locked contract)技术,由于安全性高的特点,被广泛应用于闪电网络[2]等生产环境中。


虽然当前阶段跨链原子交换并未获得广泛的用户认可,但其无第三方、原子性的优点非常符合比特币去中心化的原则,所以前景被市场所看好,许多主流虚拟货币都已完成了跨链原子交换的开源实现。随着数字货币技术和市场的成熟,跨链原子交换应该会有更多应用场景。比如跨链的大额交易可以用这项技术直接在链上完成,而不需要借助中心化交易所被收手续费。


相关工作

由于不同区块链使用的支付脚本不同,所以跨链原子交换有多个版本的编程实现。有基于比特币支付脚本的[3],实现了BTC、BCH、LTC等BTC系的数字货币之间的交换。还有基于Solidity的[4],实现了Ethereum系的数字货币以及链上ERC20货币之间的交换。swap.online项目将BTC系和Ethereum系数字货币的交换都实现了,还增加了EOS实现[5],并做了一个给用户进行交易撮合的产品[6]。还有一款钱包产品Atomic Wallet [7]也实现了各种数字货币的跨链原子交换和交易撮合功能,但是其代码并未开源。


QTUM既支持支付脚本,又支持Solidity,所以是可以用两种方式实现跨链原子交换的。但是作为前期的PoC,可以考虑最简单的方式,基于Decred的支付脚本[3]进行实现。这种方式开发量小,可以快速兼容和BTC的交换。

系统介绍

最终实现代码已经上传至Github [8],以下将介绍其原理和操作过程。

01

原理

HTLC的基本原理在文章[9]中已经有一定的介绍,并且有对应的中文译文[10]。以下将更多介绍其在比特币支付脚本中的实现方式。

以拥有Qtum的A用户和拥有Bitcoin的B用户之间的跨链原子交换为例,交换过程如下:

  1. A用户在Qtum上initiate一个合约脚本,并将时间锁规则放入合约中,向B用户转移QTUM。

  2. B用户audit审计合约。

  3. 如果合约审核通过,B用户在Bitcoin上paticipate一个合约脚本,向A用户支付Bitcoin代币。

  4. A用户audit审计合约。

  5. 如果合约审核通过,A用户则在Bitcoin上执行redeem提取Bitcoin代币。

  6. B用户根据A的提取交易extractsecret

  7. B在Qtum上执行redeem提取QTUM。

  8. 如果到达时间锁所规定的时间,而接收方还没有提取代币,则合约发起方可以refund收回代币。

在跨链原子交换中,运用到脚本支付。基于脚本支付的代币的交易验证引擎依赖于两类脚本来验证交易:一个锁定脚本和一个解锁脚本。锁定脚本是一个放在一个输出值上的“障碍”,同时它明确了今后花费这笔输出的条件。解锁脚本是一个“解决”或满足被锁定脚本在一个输出上设定的花费条件的脚本,同时它将允许输出被消费。脚本语言通过从左至右地处理每个项目的方式执行脚本。数字(常数)被推送至堆栈,操作符向堆栈推送(或移除)一个或多个参数,对它们进行处理,甚至可能会向堆栈推送一个结果。


基于哈希时间锁的跨链原子交换在初始化合约的时候,会将时间锁的规则写入到脚本了,生成一个锁定脚本,用于代币的提取。当接收方用户进行代币的提取,或者当时间到达时间锁所设定的时间后,合约生成方进行代币回收的时候,会生成一个解锁脚本,当解锁脚本与锁定脚本相匹配,用户可以使用这部分代币。


初始化合约时,锁定脚本的规则如下:

OP_IF OP_SIZE secretSize OP_EQUALVERIFY OP_SHA256 secretHash OP_EQUALVERIFY OP_DUP OP_HASH160 pubkHash OP_ELSE locktime

OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 pubkHash OP_ENDIF OP_EQUALVERIFY OP_CHECKSIG


其中 OP_IF 是当接收方提取代币时执行的规则,OP_ELSE 是当到达时间锁规定的时间后,接收方还未提取代币,则合约发起方提取代币执行的规则。


当接收方提取代币时,解锁脚本与锁定脚本的组合脚本为:

sig pubkey secret OP_SIZE secretSize OP_EQUALVERIFY OP_SHA256 secretHash OP_EQUALVERIFY OP_DUP OP_HASH160 pubkHash OP_EQUALVERIFY

OP_CHECKSIG

则解锁过程为:

当到达时间锁规定的时间后,接收方还未提取代币,则合约方提取代币,解锁脚本与锁定脚本的组合脚本为:

sig pubkey secret locktime

OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 pubkHash OP_EQUALVERIFY OP_CHECKSIG

则解锁过程为:

02

操作

以下将展示一次QTUM和BTC的交换,以1.2345个QTUM换0.05678个BTC,操作均在测试网上进行。最终的交易如下:

  1. initiate 1.2345 Qtum: https://testnet.qtum.info/tx/b86702053a9e57005742b3dffae8e13176e75a4b993addb76cf7da7efbc64429

  2. participate 0.05678 Bitcoin: https://www.blocktrail.com/tBTC/tx/63f5cda9b5389dc7584a873481b0ea66f43f6b984a2c2bb476d2c834d52c8619

  3. redeem 0.05678 bitcoin: https://www.blocktrail.com/tBTC/tx/9b2d692e8ae766d60397561d9084d6b38236f8218b4db6bf68ce1dbd8c7215e1

  4. redeem 1.2345 qtum: https://testnet.qtum.info/tx/1b49df250df609bab21d54ff5f8f069cdc9dcb107791283b14378836c7688918


操作过程如下:

1、启动节点。注意在启动最新版本Bitcoin Core的时候,需要在启动命名中加入参数以保证相关命令的运行。

$ bitcoind -testnet -daemon -rpcuser=atomic -rpcpassword=atomic -deprecatedrpc=signrawtransaction -addresstype=legacy

$ qtumd -testnet -daemon -rpcuser=atomic -rpcpassword=atomic


2、A initiate。

$ qtumatomicswap -testnet -rpcuser=atomic -rpcpass=atomic initiate qPRp4QPnmDjSzCqF2S18r8oLL9ZzWdmNz5 1.2345
warning: falling back to mempool relay fee policy
Secret: a0c3f5783304f7540c84410f5170eff6c7109de35bef7414c57358961863b7fc
Secret hash: fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa8
Contract fee: 0.001488 QTUM (0.00401078 qtum/kB)

Refund fee: 0.001188 QTUM (0.00408247 qtum/kB)



Contract (mPA3UbaG755ofjyCKS4JHARyX4pB7mfPFv):

6382012088a820fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa88876a9144062370837272caa0d3037b87cb9e85c022810546704842c125cb17576a914032bb1143efd651a8c6204bd484e14acbbb82d2f6888ac



Contract transaction (b86702053a9e57005742b3dffae8e13176e75a4b993addb76cf7da7efbc64429):

020000000242df4d172a748e7db6f3bcd4f0ff6cfcdeb08ad00be63a0f52512594659bce960b0000006a47304402201e6f0462f6b1ab5e27b875f626d49d84adfc20ec0eee07e1ab5608d2deb53304022057c124b780fa2dd8090a57121addb7bb0de7642d1c2638d5833a1f7bfef7f3d2012102b4bf8cb4fd61e225ec5bf3ed7260b0a0145228fcbe627fd2162dacf382853853feffffff6be7923ffb086162d4ea581ec1d009fe19f23cff72d684dfb93c121545620cd00b0000006b483045022100f1ae60435cda95686c60fa23d75e6354e66d767d98c20971984b3fbf20d3059602204e77f6acefd1061d32047abc3cb93f1fc8602b1dc53ffbb1341c6c10f08477a80121029c3d5e11b10ad9f703a1a0d5d668fe697780e46538e0e4a28bc8fd168ac1aee0feffffff02c8208500000000001976a9145eecdd1a51d0a0c624cb46e6f09344e6fd17efbd88ac90b25b070000000017a9144c8993e9fbc077f91320aec2d4e21dd7a8b4b0d38700000000



Refund transaction (6dddd10d3b79c28e03e44b9dfaa22259a951886150cf60c0c21b9e79792d06c9):

02000000012944c6fb7edaf76cb7dd3a994b5ae77631e1e8fadfb3425700579e3a050267b801000000ce47304402206976063f18c67064f6f39b7d46e83ada35a1e09633640936923bded0f113b84e0220629e875916b43f12d99ae82bc52e6ef6322a52430d79c50673b740b4e537912301210306689a0d355d58b45a32ac79aed55686554f72946b64353948db02559d543827004c616382012088a820fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa88876a9144062370837272caa0d3037b87cb9e85c022810546704842c125cb17576a914032bb1143efd651a8c6204bd484e14acbbb82d2f6888ac000000000180e25907000000001976a91499701f205fea8abd2554abeea2cc9c7ebe9d415a88ac842c125c



Publish contract transaction? [y/N] y

Published contract transaction (b86702053a9e57005742b3dffae8e13176e75a4b993addb76cf7da7efbc64429)

3、B audit。

$ qtumatomicswap -testnet -rpcuser=atomic -rpcpass=atomic auditcontract 6382012088a820fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa88876a9144062370837272caa0d3037b87cb9e85c022810546704842c125cb17576a914032bb1143efd651a8c6204bd484e14acbbb82d2f6888ac 020000000242df4d172a748e7db6f3bcd4f0ff6cfcdeb08ad00be63a0f52512594659bce960b0000006a47304402201e6f0462f6b1ab5e27b875f626d49d84adfc20ec0eee07e1ab5608d2deb53304022057c124b780fa2dd8090a57121addb7bb0de7642d1c2638d5833a1f7bfef7f3d2012102b4bf8cb4fd61e225ec5bf3ed7260b0a0145228fcbe627fd2162dacf382853853feffffff6be7923ffb086162d4ea581ec1d009fe19f23cff72d684dfb93c121545620cd00b0000006b483045022100f1ae60435cda95686c60fa23d75e6354e66d767d98c20971984b3fbf20d3059602204e77f6acefd1061d32047abc3cb93f1fc8602b1dc53ffbb1341c6c10f08477a80121029c3d5e11b10ad9f703a1a0d5d668fe697780e46538e0e4a28bc8fd168ac1aee0feffffff02c8208500000000001976a9145eecdd1a51d0a0c624cb46e6f09344e6fd17efbd88ac90b25b070000000017a9144c8993e9fbc077f91320aec2d4e21dd7a8b4b0d38700000000

Contract address: mPA3UbaG755ofjyCKS4JHARyX4pB7mfPFv

Contract value: 1.2345 QTUM

Recipient address: qPRp4QPnmDjSzCqF2S18r8oLL9ZzWdmNz5

Author's refund address: qHr9XMrc7Q93FBCnvdCwJJtcWTuogXfzpc



Secret hash: fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa8



Locktime: 2018-12-13 09:55:16 +0000 UTC

Locktime reached in 47h38m32s

4、B participate。

$ btcatomicswap -testnet -rpcuser=atomic -rpcpass=atomic participate mx3ZYeAMqvHFsuHj1DN3CTFVHY6YWDZVxx 0.05678 fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa8

Contract fee: 0.00000223 BTC (0.00001000 BTC/kB)

Refund fee: 0.00000297 BTC (0.00001021 BTC/kB)



Contract (2Mvx5aToh6aABp9EdjsGjEr1amAXzF3CbYB):

6382012088a820fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa88876a914b54beaf9a465c3665530c2b12d789da54b10fc806704d3db105cb17576a9142c6328c6e3c7acb7c0176389ecb4285c6b290bd06888ac



Contract transaction (63f5cda9b5389dc7584a873481b0ea66f43f6b984a2c2bb476d2c834d52c8619):

0200000001d0dc54d6dc08140c2a1bd52c1bca85ec37c54fc122b16b5fa9aab4bfb33d8e80010000006a47304402205fdb761150dd1fe088d55ae959bc825ff7bd5151cf14386a1249834c6c6de18102201e1a1194fc82fb3f4c1292a2cf26c5e5a6f5e0de559c1b6cc13c1babc115ea11012102f60d73085b9133f48e9df862016d7750f0c8554b29e7c2955d785a49dc5dc0acfeffffff0230d72600000000001976a9146c1ca2acd60cb0aeec2dd3a67ab8fe2a06df383b88acb0a356000000000017a91428a2692f75c4b6af28c41ee8d243af6c7b2e7db88700000000



Refund transaction (6bf671e4827655b1d3b18bef8795bf235bdd55fbf19d9f46f3f2b6bb966fd3c8):

020000000119862cd534c8d276b42b2c4a986b3ff466eab08134874a58c79d38b5a9cdf56301000000ce473044022024abf5dbadea2738f7d4911d45c7be36a35e03925810f2ba22f4fc702f302598022030b6cc22ef6cbed7ffed364ebe276d923e1253dd40ea1dbd0c23e99455fc4d98012103d83135bb45c605343a564f7815b52760f24ebd6cb33e8de28b315fdb8400bcdd004c616382012088a820fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa88876a914b54beaf9a465c3665530c2b12d789da54b10fc806704d3db105cb17576a9142c6328c6e3c7acb7c0176389ecb4285c6b290bd06888ac000000000187a25600000000001976a91451f7fd1ec4a587315b20293e933e5c7bdf5be96688acd3db105c



Publish contract transaction? [y/N] y

Published contract transaction (63f5cda9b5389dc7584a873481b0ea66f43f6b984a2c2bb476d2c834d52c8619)

5、A audit。

$ btcatomicswap -testnet -rpcuser=atomic -rpcpass=atomic auditcontract 6382012088a820fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa88876a914b54beaf9a465c3665530c2b12d789da54b10fc806704d3db105cb17576a9142c6328c6e3c7acb7c0176389ecb4285c6b290bd06888ac 0200000001d0dc54d6dc08140c2a1bd52c1bca85ec37c54fc122b16b5fa9aab4bfb33d8e80010000006a47304402205fdb761150dd1fe088d55ae959bc825ff7bd5151cf14386a1249834c6c6de18102201e1a1194fc82fb3f4c1292a2cf26c5e5a6f5e0de559c1b6cc13c1babc115ea11012102f60d73085b9133f48e9df862016d7750f0c8554b29e7c2955d785a49dc5dc0acfeffffff0230d72600000000001976a9146c1ca2acd60cb0aeec2dd3a67ab8fe2a06df383b88acb0a356000000000017a91428a2692f75c4b6af28c41ee8d243af6c7b2e7db88700000000

Contract address: 2Mvx5aToh6aABp9EdjsGjEr1amAXzF3CbYB

Contract value: 0.05678 BTC

Recipient address: mx3ZYeAMqvHFsuHj1DN3CTFVHY6YWDZVxx

Author's refund address: mjZepChJitAU8XYveyYGWZmV8BK3z6oDPj



Secret hash: fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa8



Locktime: 2018-12-12 09:58:43 +0000 UTC

Locktime reached in 23h39m57s

6、A redeem

$ btcatomicswap -testnet -rpcuser=atomic -rpcpass=atomic redeem 6382012088a820fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa88876a914b54beaf9a465c3665530c2b12d789da54b10fc806704d3db105cb17576a9142c6328c6e3c7acb7c0176389ecb4285c6b290bd06888ac 0200000001d0dc54d6dc08140c2a1bd52c1bca85ec37c54fc122b16b5fa9aab4bfb33d8e80010000006a47304402205fdb761150dd1fe088d55ae959bc825ff7bd5151cf14386a1249834c6c6de18102201e1a1194fc82fb3f4c1292a2cf26c5e5a6f5e0de559c1b6cc13c1babc115ea11012102f60d73085b9133f48e9df862016d7750f0c8554b29e7c2955d785a49dc5dc0acfeffffff0230d72600000000001976a9146c1ca2acd60cb0aeec2dd3a67ab8fe2a06df383b88acb0a356000000000017a91428a2692f75c4b6af28c41ee8d243af6c7b2e7db88700000000 a0c3f5783304f7540c84410f5170eff6c7109de35bef7414c57358961863b7fc

Redeem fee: 0.0000033 BTC (0.00001015 BTC/kB)



Redeem transaction (9b2d692e8ae766d60397561d9084d6b38236f8218b4db6bf68ce1dbd8c7215e1):

020000000119862cd534c8d276b42b2c4a986b3ff466eab08134874a58c79d38b5a9cdf56301000000f0483045022100bed778c8462df6ed1f4105355816e7411a4482de2e1af670c8e96f4f1b107f51022044b6948bdecc6e45ddc760bd71fa14537664a3b4d5944bd4fe89a6b8feaa1f0a012103f534052289ba6610c300a4b49bf2337bf01f48f806f53c74609ecbcd917b219f20a0c3f5783304f7540c84410f5170eff6c7109de35bef7414c57358961863b7fc514c616382012088a820fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa88876a914b54beaf9a465c3665530c2b12d789da54b10fc806704d3db105cb17576a9142c6328c6e3c7acb7c0176389ecb4285c6b290bd06888acffffffff0166a25600000000001976a91431355ae3549c6b0b39ec9c598178e74716096a6588acd3db105c

Publish redeem transaction? [y/N] y

Published redeem transaction (9b2d692e8ae766d60397561d9084d6b38236f8218b4db6bf68ce1dbd8c7215e1)

7、B extractsecret。

$ btcatomicswap -testnet -rpcuser=atomic -rpcpass=atomic extractsecret 020000000119862cd534c8d276b42b2c4a986b3ff466eab08134874a58c79d38b5a9cdf56301000000f0483045022100bed778c8462df6ed1f4105355816e7411a4482de2e1af670c8e96f4f1b107f51022044b6948bdecc6e45ddc760bd71fa14537664a3b4d5944bd4fe89a6b8feaa1f0a012103f534052289ba6610c300a4b49bf2337bf01f48f806f53c74609ecbcd917b219f20a0c3f5783304f7540c84410f5170eff6c7109de35bef7414c57358961863b7fc514c616382012088a820fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa88876a914b54beaf9a465c3665530c2b12d789da54b10fc806704d3db105cb17576a9142c6328c6e3c7acb7c0176389ecb4285c6b290bd06888acffffffff0166a25600000000001976a91431355ae3549c6b0b39ec9c598178e74716096a6588acd3db105c fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa8

Secret: a0c3f5783304f7540c84410f5170eff6c7109de35bef7414c57358961863b7fc

8、B redeem。

$ qtumatomicswap -testnet -rpcuser=atomic -rpcpass=atomic redeem 6382012088a820fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa88876a9144062370837272caa0d3037b87cb9e85c022810546704842c125cb17576a914032bb1143efd651a8c6204bd484e14acbbb82d2f6888ac 020000000242df4d172a748e7db6f3bcd4f0ff6cfcdeb08ad00be63a0f52512594659bce960b0000006a47304402201e6f0462f6b1ab5e27b875f626d49d84adfc20ec0eee07e1ab5608d2deb53304022057c124b780fa2dd8090a57121addb7bb0de7642d1c2638d5833a1f7bfef7f3d2012102b4bf8cb4fd61e225ec5bf3ed7260b0a0145228fcbe627fd2162dacf382853853feffffff6be7923ffb086162d4ea581ec1d009fe19f23cff72d684dfb93c121545620cd00b0000006b483045022100f1ae60435cda95686c60fa23d75e6354e66d767d98c20971984b3fbf20d3059602204e77f6acefd1061d32047abc3cb93f1fc8602b1dc53ffbb1341c6c10f08477a80121029c3d5e11b10ad9f703a1a0d5d668fe697780e46538e0e4a28bc8fd168ac1aee0feffffff02c8208500000000001976a9145eecdd1a51d0a0c624cb46e6f09344e6fd17efbd88ac90b25b070000000017a9144c8993e9fbc077f91320aec2d4e21dd7a8b4b0d38700000000 a0c3f5783304f7540c84410f5170eff6c7109de35bef7414c57358961863b7fc

Redeem fee: 0.00253191 QTUM (0.00779049 qtum/kB)



Redeem transaction (1b49df250df609bab21d54ff5f8f069cdc9dcb107791283b14378836c7688918):

02000000012944c6fb7edaf76cb7dd3a994b5ae77631e1e8fadfb3425700579e3a050267b801000000f0483045022100a2464fc967f0f7451c2f3f6afeb7c6c67bf05088992f601ef023062567a1b347022062f92953c335cca48c7048415b00a718155ac473c97d3f6b056ced02fa33f2b80121039d6689ba6702d454c59770a6690d881f37fd143236ee337669f25b7e6e55c55220a0c3f5783304f7540c84410f5170eff6c7109de35bef7414c57358961863b7fc514c616382012088a820fe7232f58f3851d23c68e689da9088effeef66958abb6da3328d3a26aa43faa88876a9144062370837272caa0d3037b87cb9e85c022810546704842c125cb17576a914032bb1143efd651a8c6204bd484e14acbbb82d2f6888acffffffff0189d55707000000001976a914c7034970f9dda671b5590e99c811b4b672ee22cb88ac842c125c



Publish redeem transaction? [y/N] y

Published redeem transaction (1b49df250df609bab21d54ff5f8f069cdc9dcb107791283b14378836c7688918)


未来工作

由于Qtum跨链原子交换的代码完全开源,所以我们鼓励开发者基于这份代码实现跨链应用,从而实现各个区块链系统和Qtum的交互。


参考文献

[1] Atomic cross-chain swaps. https://arxiv.org/pdf/1801.09515.pdf.

[2] The bitcoin lightning network: scalable off-chain instant payments. https://lightning.network/lightning-network-paper.pdf.

[3] Decred atomic swap implementation. https://github.com/decred/atomicswap.

[4] Secto-io atomic swap implementation. https://github.com/secto-io/atomic-swap.

[5] Swap.online atomic swap implementation. https://github.com/swaponline/swap.core.

[6] Swap.online. https://swap.online/.

[7] Atomic wallet. https://atomicwallet.io/.

[8] Qtum atomic swap implementation. https://github.com/qtumatomicswap/atomicswap.

[9] Atomic swaps. https://bitcointechtalk.com/atomic-swaps-d6ca26b680fe.

[10] 原子跨链交易. https://www.jianshu.com/p/f1b2168eea21.




声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/468372
推荐阅读
相关标签
  

闽ICP备14008679号