Bytom 交易说明(账户管理模式) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Bytom
V2EX    区块链

Bytom 交易说明(账户管理模式)

  •  
  •   Bytom 2018-08-24 10:32:42 +08:00 1419 次点击
    这是一个创建于 2605 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比原项目仓库:

    Github 地址: https://github.com/Bytom/bytom

    Gitee 地址: https://gitee.com/BytomBlockchain/bytom

    该部分主要针对用户使用 bytom 自带的账户模式发送交易

    <2>1、构建交易

    API 接口 build-transaction,代码api/transact.go#L120

    以标准的非 BTM 资产转账交易为例,资产 ID 为全 F 表示 BTM 资产,在该示例中 BTM 资产仅作为手续费,该交易表示花费 99 个特定的资产到指定地址中。其中构建交易的输入请求 json 格式如下:

    { "base_transaction": null, "actions": [ { "account_id": "0ER7MEFGG0A02", "amount": 20000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "type": "spend_account" }, { "account_id": "0ER7MEFGG0A02", "amount": 99, "asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f", "type": "spend_account" }, { "amount": 99, "asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f", "address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me", "type": "control_address" } ], "ttl": 0, "time_range": 0 } 

    对应源代码的请求对象如下:

    // BuildRequest is main struct when building transactions type BuildRequest struct { Tx *types.TxData `json:"base_transaction"` Actions []map[string]interface{} `json:"actions"` TTL json.Duration `json:"ttl"` TimeRange uint64 `json:"time_range"` } 

    结构字段说明如下:

    • Tx 交易的TxData部分,该字段为预留字段,为空即可
    • TTL 构建交易的生存时间(单位为毫秒),意味着在该时间范围内,已经缓存的 utxo 不能用于再一次 build 交易,除非剩余的 utxo 足以构建一笔新的交易,否则会报错。当ttl为 0 时会被默认设置为 600s,即 5 分钟
    • TimeRange 时间戳,意味着该交易将在该时间戳(区块高度)之后不会被提交上链,为了防止交易在网络中传输延迟而等待太久时间,如果交易没有在特定的时间范围内被打包,该交易便会自动失效
    • Actions 交易的actions结构,所有的交易都是由 action 构成的,map类型的interface{}保证了 action 类型的可扩展性。其中 action 中必须包含 type 字段,用于区分不同的 action 类型,action主要包含inputoutput两种类型,其详细介绍如下:
      • input action 类型:
        • issue 发行资产
        • spend_account 以账户的模式花费 utxo
        • spend_account_unspent_output 直接花费指定的 utxo
      • output action 类型:
        • control_address 接收方式为地址模式
        • control_program 接收方式为( program )合约模式
        • retire 销毁资产

    注意事项

    • 一个交易必须至少包含一个 input 和 output ( coinbase 交易除外,因为 coinbase 交易是由系统产生,故不在此加以描述),否则交易将会报错。
    • 除了 BTM 资产(所有交易都是以 BTM 资产作为手续费)之外,其他资产在构建 input 和 output 时,所有输入和输出的资产总和必须相等,否则交易会报出输入输出不平衡的错误信息。
    • 交易的手续费: 所有 inputs 的 BTM 资产数量 - 所有 outputs 的 BTM 资产数量
    • 交易中的资产 amount 都是 neu 为单位的,BTM 的单位换算如下:1 BTM = 1000 mBTM = 100000000 neu

    action 简介

    下面对构建交易时用到的各种action类型进行详细说明:

    issue

    issueAction结构体源代码如下:

    type issueAction struct { assets *Registry bc.AssetAmount } type AssetAmount struct { AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"` Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"` } 

    结构字段说明如下:

    • assets 主要用于资产的管理,无需用户设置参数
    • AssetAmount 表示用户需要发行的资产 ID 和对应的资产数目,这里的AssetID需要通过create-asset创建,并且这里不能使用BTM的资产 ID

    issueActionjson格式为:

    { "amount": 100000000, "asset_id": "3152a15da72be51b330e1c0f8e1c0db669269809da4f16443ff266e07cc43680", "type": "issue" } 

    例如发行一笔资产的交易示例如下: (该交易表示发行数量为900000000assetID42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f的资产到接收地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中手续费为20000000neu 的 BTM 资产)

    { "base_transaction": null, "actions": [ { "account_id": "0ER7MEFGG0A02", "amount": 20000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "type": "spend_account" }, { "amount": 900000000, "asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f", "type": "issue" }, { "amount": 900000000, "asset_id": "42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f", "address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me", "type": "control_address" } ], "ttl": 0, "time_range": 0 } 

    spend_account

    spendAction结构体源代码如下:

    type spendAction struct { accounts *Manager bc.AssetAmount AccountID string `json:"account_id"` ClientToken *string `json:"client_token"` } type AssetAmount struct { AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"` Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"` } 

    结构字段说明如下:

    • accounts 主要用于账户的管理,无需用户设置参数
    • AccountID 表示需要花费资产的账户 ID
    • AssetAmount 表示花费的资产 ID 和对应的资产数目
    • ClientToken 表示 Reserve 用户 UTXO 的限制条件,目前不填或为空即可

    spendActionjson格式为:

    { "account_id": "0BF63M2U00A04", "amount": 2000000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "type": "spend_account" } 

    例如转账一笔资产的交易示例如下: (该交易表示通过账户的方式转账100000000neu 的 BTM 资产到地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中手续费20000000neu = 输入 BTM 资产数量 - 输出 BTM 资产数量)

    { "base_transaction": null, "actions": [ { "account_id": "0ER7MEFGG0A02", "amount": 120000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "type": "spend_account" }, { "amount": 100000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me", "type": "control_address" } ], "ttl": 0, "time_range": 0 } 

    spend_account_unspent_output

    spendUTXOAction结构体源代码如下:

    type spendUTXOAction struct { accounts *Manager OutputID *bc.Hash `json:"output_id"` ClientToken *string `json:"client_token"` } 

    结构字段说明如下:

    • accounts 主要用于账户的管理,无需用户设置参数
    • OutputID 表示需要花费的 UTXO 的 ID,可以根据list-unspent-outputs查询可用的 UTXO,其中OutputID对应该 API 返回结果的id字段
    • ClientToken 表示 Reserve 用户 UTXO 的限制条件,目前不填或为空即可

    spendUTXOActionjson格式为:

    { "type": "spend_account_unspent_output", "output_id": "58f29f0f85f7bd2a91088bcbe536dee41cd0642dfb1480d3a88589bdbfd642d9" } 

    例如通过花费 UTXO 的方式转账一笔资产的交易示例如下: (该交易表示通过直接花费 UTXO 的方式转账100000000neu 的 BTM 资产到地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中手续费 = 输入 BTM 资产的 UTXO 值 - 输出 BTM 资产数量)

    { "base_transaction": null, "actions": [ { "output_id": "58f29f0f85f7bd2a91088bcbe536dee41cd0642dfb1480d3a88589bdbfd642d9", "type": "spend_account_unspent_output" }, { "amount": 100000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me", "type": "control_address" } ], "ttl": 0, "time_range": 0 } 

    control_address

    controlAddressAction结构体源代码如下:

    type controlAddressAction struct { bc.AssetAmount Address string `json:"address"` } type AssetAmount struct { AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"` Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"` } 

    结构字段说明如下:

    • Address 表示接收资产的地址,可以根据 create-account-receiver API 接口创建地址
    • AssetAmount 表示接收的资产 ID 和对应的资产数目

    controlAddressActionjson格式为:

    { "amount": 100000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "address": "bm1q50u3z8empm5ke0g3ngl2t3sqtr6sd7cepd3z68", "type": "control_address" } 

    例如转账一笔资产的交易示例如下: (该交易表示通过账户的方式转账100000000neu 的 BTM 资产到地址sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me中, 其中control_address类型表示以地址作为接收方式)

    { "base_transaction": null, "actions": [ { "account_id": "0ER7MEFGG0A02", "amount": 120000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "type": "spend_account" }, { "amount": 100000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "address": "sm1qxe4jwhkekgnxkezu7xutu5gqnnpmyc8ppq98me", "type": "control_address" } ], "ttl": 0, "time_range": 0 } 

    control_program

    controlProgramAction结构体源代码如下:

    type controlProgramAction struct { bc.AssetAmount Program json.HexBytes `json:"control_program"` } type AssetAmount struct { AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"` Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"` } 

    结构字段说明如下:

    • Program 表示接收资产的合约脚本,可以根据 create-account-receiver API 接口创建接收program(返回结果的 programaddress 是一一对应的)
    • AssetAmount 表示接收的资产 ID 和对应的资产数目

    controlProgramActionjson格式为:

    { "amount": 100000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "control_program":"0014a3f9111f3b0ee96cbd119a3ea5c60058f506fb19", "type": "control_program" } 

    例如转账一笔资产的交易示例如下: (该交易表示通过账户的方式转账100000000neu 的 BTM 资产到接收program(跟address是一一对应的)0014a3f9111f3b0ee96cbd119a3ea5c60058f506fb19中, 其中control_program类型表示以program作为接收方式)

    { "base_transaction": null, "actions": [ { "account_id": "0ER7MEFGG0A02", "amount": 120000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "type": "spend_account" }, { "amount": 100000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "control_program": "0014a3f9111f3b0ee96cbd119a3ea5c60058f506fb19", "type": "control_program" } ], "ttl": 0, "time_range": 0 } 

    retire

    retireAction结构体源代码如下:

    type retireAction struct { bc.AssetAmount } type AssetAmount struct { AssetId *AssetID `protobuf:"bytes,1,opt,name=asset_id,json=assetId" json:"asset_id,omitempty"` Amount uint64 `protobuf:"varint,2,opt,name=amount" json:"amount,omitempty"` } 

    结构字段说明如下:

    • AssetAmount 表示销毁的资产 ID 和对应的资产数目

    retireActionjson格式为:

    { "amount": 900000000, "asset_id": "3152a15da72be51b330e1c0f8e1c0db669269809da4f16443ff266e07cc43680", "type": "retire" } 

    例如销毁一笔资产的交易示例如下: (该交易表示通过账户的方式将100000000neu 的 BTM 资产销毁, retire表示销毁指定数量的资产)

    { "base_transaction": null, "actions": [ { "account_id": "0ER7MEFGG0A02", "amount": 120000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "type": "spend_account" }, { "amount": 100000000, "asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "type": "retire" } ], "ttl": 0, "time_range": 0 } 

    build-transaction的输入构造完成之后,便可以通过 http 的调用方式进行发送交易,构建交易请求成功之后返回的 json 结果如下:

    { "allow_additional_actions": false, "raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a077301000161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf456010003013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100", "signing_instructions": [ { "position": 0, "witness_components": [ { "keys": [ { "derivation_path": [ "010100000000000000", "0100000000000000" ], "xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8" } ], "quorum": 1, "signatures": null, "type": "raw_tx_signature" }, { "type": "data", "value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5" } ] }, { "position": 1, "witness_components": [ { "keys": [ { "derivation_path": [ "010100000000000000", "0800000000000000" ], "xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8" } ], "quorum": 1, "signatures": null, "type": "raw_tx_signature" }, { "type": "data", "value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419" } ] } ] } 

    对应响应对象的源代码如下:

    // Template represents a partially- or fully-signed transaction. type Template struct { Transaction *types.Tx `json:"raw_transaction"` SigningInstructions []*SigningInstruction `json:"signing_instructions"` // AllowAdditional affects whether Sign commits to the tx sighash or // to individual details of the tx so far. When true, signatures // commit to tx details, and new details may be added but existing // ones cannot be changed. When false, signatures commit to the tx // as a whole, and any change to the tx invalidates the signature. AllowAdditional bool `json:"allow_additional_actions"` } 

    结构字段说明如下:

    • Transaction 交易相关信息,该字段包含TxDatabc.Tx两个部分:
      • TxData 表示给用户展示的交易数据部分,该部分对用户可见
        • Version 交易版本
        • SerializedSize 交易序列化之后的 size
        • TimeRange 交易提交上链的最大时间戳(区块高度)(主链区块高度到达该时间戳(区块高度)之后,如果交易没有被提交上链,该交易便会失效)
        • Inputs 交易输入
        • Outputs 交易输出
      • bc.Tx 表示系统中处理交易用到的转换结构,该部分对用户不可见,故不做详细描述
    • SigningInstructions 交易的签名信息
      • Positioninput action签名的位置
      • WitnessComponentsinput action签名需要的数据信息,其中 build 交易的signaturesnull,表示没有签名; 如果交易签名成功,则该字段会存在签名信息。该字段是一个 interface 接口,主要包含 3 种不同的类型:
        • SignatureWitness 对交易模板Template中交易input action位置的合约 program 进行哈希,然后对 hash 值进行签名
          • signatures (数组类型)交易的签名,sign-transaction执行完成之后才会有值存在
          • keys (数组类型)包含主公钥xpub和派生路径derivation_path,通过它们可以在签名阶段找到对应的派生私钥child_xprv,然后使用派生私钥进行签名
          • quorum 账户key 的个数,必须和上面的keys的长度相等。如果quorum 等于 1,则表示单签账户,否则为多签账户
          • program 签名的数据部分,program的 hash 值作为签名数据。如果program为空,则会根据当前交易 ID 和对应 action 位置的 InputID 两部分生成一个 hash,然后把它们作为指令数据自动构造一个program
        • RawTxSigWitness 对交易模板Template的交易 ID 和对应input action位置的 InputID(该字段位于 bc.Tx 中)进行哈希,然后对 hash 值进行签名
          • signatures (数组类型)交易的签名,sign-transaction执行完成之后才会有值存在
          • keys (数组类型)包含主公钥xpub和派生路径derivation_path,通过它们可以在签名阶段找到对应的派生私钥child_xprv,然后使用派生私钥进行签名
          • quorum 账户key的个数,必须和上面的keys 的长度相等。如果quorum 等于 1,则表示单签账户,否则为多签账户
        • DataWitness 该类型无需签名,验证合约 program 的附加数据
    • AllowAdditional 是否允许交易的附加数据,如果为true,则交易的附加数据会添加到交易中,但是不会影响交易的执行的program脚本,对签名结果不会造成影响; 如果为false,则整个交易作为一个整体进行签名,任何数据的改变将影响整个交易的签名

    估算手续费

    估算手续费接口estimate-transaction-gas是对build-transaction的结果进行手续费的预估,估算的结果需要重新加到build-transaction的结果中,然后对交易进行签名和提交。其主要流程如下:

     build - estimate - build - sign - submit 

    估算手续费的输入请求 json 格式如下:

    { "transaction_template": { "allow_additional_actions": false, "raw_transaction": "070100020161015f1190c60818b4aff485c865113c802942f29ce09088cae1b117fc4c8db2292212ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8099c4d599010001160014a86c83ee12e6d790fb388345cc2e2b87056a077301000161015fb018097c4040c8dd86d95611a13c24f90d4c9d9d06b25f5c9ed0556ac8abd73442275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f80a094a58d1d0101160014068840e56af74038571f223b1c99f1b60caaf456010003013effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bfffcb9901011600140b946646626c55a52a325c8bb48de792284d9b7200013e42275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f9d9f94a58d1d01160014c8b4391bab4923a83b955170d24ee4ca5b6ec3fb00013942275aacbeda1522cd41580f875c3c452daf5174b17ba062bf0ab71a568c123f6301160014366b275ed9b2266b645cf1b8be51009cc3b260e100", "signing_instructions": [ { "position": 0, "witness_components": [ { "keys": [ { "derivation_path": [ "010100000000000000", "0100000000000000" ], "xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8" } ], "quorum": 1, "signatures": null, "type": "raw_tx_signature" }, { "type": "data", "value": "d174db6506e35f2decb5be148c2984bfd0f6c67f043365bf642d1af387c04fd5" } ] }, { "position": 1, "witness_components": [ { "keys": [ { "derivation_path": [ "010100000000000000", "0800000000000000" ], "xpub": "de0db655c091b2838ccb6cddb675779b0a9a4204b122e61699b339867dd10eb0dbdc926882ff6dd75c099c181c60d63eab0033a4b0a4d0a8c78079e39d7ad1d8" } ], "quorum": 1, "signatures": null, "type": "raw_tx_signature" }, { "type": "data", "value": "05cdbcc705f07ad87521835bbba226ad7b430cc24e5e3f008edbe61540535419" } ] } ] } } 

    对应响应对象的源代码如下:

    type request struct{ TxTemplate txbuilder.Template `json:"transaction_template"` } // Template represents a partially- or fully-signed transaction. type Template struct { Transaction *types.Tx `json:"raw_transaction"` SigningInstructions []*SigningInstruction `json:"signing_instructions"` // AllowAdditional affects whether Sign commits to the tx sighash or // to individual details of the tx so far. When true, signatures // commit to tx details, and new details may be added but existing // ones cannot be changed. When false, signatures commit to the tx // as a whole, and any change to the tx invalidates the signature. AllowAdditional bool `json:"allow_additional_actions"` } 

    其中TxTemplate相关字段的说明见 build-transaction 的结果描述

    调用estimate-transaction-gas接口成功之后返回的 json 结果如下:

    { "total_neu": 5000000, "storage_neu": 3840000, "vm_neu": 1419000 } 

    对应响应对象的源代码如下:

    // EstimateTxGasResp estimate transaction consumed gas type EstimateTxGasResp struct { TotalNeu int64 `json:"total_neu"` StorageNeu int64 `json:"storage_neu"` VMNeu int64 `json:"vm_neu"` } 

    结构字段说明如下:

    • TotalNeu 预估的总手续费(单位为 neu ),该值直接加到 build-transaction 的 BTM 资产输入 action 中即可
    • StorageNeu 存储交易的手续费
    • VMNeu 运行虚拟机的手续费
    1 条回复    2018-08-24 10:35:01 +08:00
    Bytom
        1
    Bytom  
    OP
       2018-08-24 10:35:01 +08:00
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3683 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 33ms UTC 10:21 PVG 18:21 LAX 03:21 JFK 06:21
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86