本篇文章所分析都基于这样一种场景
系统中钱包发起的交易则在数据库中写入提现记录(相对于发起交易的地址而言,消费绑定在其地址上的未消费输出-UTXO为提现到其他地址操作),而这笔交易产生的交易输出,相对于绑定在输出上的地址而言则为充值操作。
那么系统外部对钱包地址发起的交易,对于位于该钱包的地址来说则为充值操作。
另外这里约定系统发起的交易都会在数据库中写入一条 提现记录,因为不管这笔交易的输出对象为钱包内部的地址或者钱包外部的地址,对于发起者而言都是 提现操作,所以在数据库中添加了一条 提现记录
而在数据库中添加 充值记录 的场景是 “和钱包中地址有关交易” 被区块链首次确认时才发生。
Bitcoindd-core 钱包内部地址之间发起的交易,钱包之间的地址发起的交易对于自己的钱包来说都会生成一个提现记录,并标记为等待区块链确认状态(后面转账到钱包需要等待管理员审核通过之后状态才推进到等待区块链确认)
有三种情况可触发 walletnotify 回调:
-
收到比特币
- 如果是钱包内部的交易,则已经存在提现记录,状态为等待区块链确认,此时不能添加充值记录
。 - 如果是从外部转到钱包,不存在提现记录,此时不能添加充值记录。
- 如果是钱包内部的交易,则已经存在提现记录,状态为等待区块链确认,此时不能添加充值记录
发出比特币
存在提现记录,状态为等待区块链确认,此时还不能添加充值-
钱包内比特币交易收到区块链首次确认
- 交易是钱包发起(转账到钱包、转账到外部区块链地址),此时可以添加充值记录。
- 交易由钱包外部发起(对钱包而言是充值操作),不存在提现记录,此时可以添加充值记录。
得出结论
- 若交易是由钱包发起的,则存在提现记录
- 若交易由其他交易所发起,则不存在提现记录
反推:
- 存在提现记录(钱包内部转账,钱包转到区块链-内部充值)则该交易由钱包发起
- 不存在提现记录(外部充值)则该交易由交易所发起
结合钱包内部转账(分为内部提现和内部充值)、钱包外部充值三种情况产生交易和数据库中保存的提现记录分析
- 钱包内部地址(这里讨论两个地址之间发生交易)发起一次交易,产生两次回调,返回的 txid 相同(存在提现记录,状态为非 confirmed ,不需要写充值记录)
- 钱包向外部发起一次交易,产生一次回调(存在提现记录,状态为非 confirmed ,不需要写充值记录)
- 外部向钱包发起一次交易,产生一次回调(不存在提现记录,不需要写充值记录)
- 区块链一个确认,可能产生多次回调,其中包含钱包中交易的首次确认(存在提现记录,状态为非 confirmed ,需要写充值记录且提现记录状态更改为 confirmed)
上面提到的四种回调,前面三种不需要写充值记录,最后一种需要写充值记录并更改状态记录为已被确认。
当有回调时,首先根据返回的 txid 检测数据库中是否存在提现记录且提现记录的状态如果为非 confirmed,有则初步可判断为1,2,4 三种交易类型,那么如何区分开1,2 和 4 这两种类型回调呢(交易和确认回调)
结论为:从数据库的交易记录表中查询是否存在 walletnotify 回调返回的 txid 和 确认状态不能区分开 1,2 和 4 这两种回调类型,那么我们解析一下 walletnotify 中确认回调和交易回调产生的 txid 详细交易记录信息。
分析交易、区块链确认产生的交易信息及特征
区块确认时产生的 walleynotify 回调返回的 txid 交易记录里面包含的信息:
trusblock@i-l9ptvup7:~$ bitcoin-cli gettransaction 83bb517c9c9397ad84ea4c561249be4ee23a4153bb6d097fba3b049b0b8bd585
{
"amount": 0.00000000,
"confirmations": 1,
"generated": true,
"blockhash": "3d5e99b6fb4cd24b6c4886b18660aa1d423e9e405510c5664ed642e21bd479a4",
"blockindex": 0,
"blocktime": 1477814070,
"txid": "83bb517c9c9397ad84ea4c561249be4ee23a4153bb6d097fba3b049b0b8bd585",
"walletconflicts": [
],
"time": 1477814070,
"timereceived": 1477814070,
"bip125-replaceable": "no",
"details": [
{
"account": "",
"address": "mhu69cMmcPKGhU5zDm5g3z8UuW4HY3WMUT",
"category": "immature",
"amount": 50.00000000,
"vout": 0
}
],
"hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0401700101ffffffff0100f2052a0100000023210269c4c2d5dc1b6ba07ca11b18fbc87c8fd978a4eabdf90447ba0d22b34937f58bac00000000"
}
交易时产生的 walletnotify 回调返回的 txid 里面的交易记录的信息(还没被确认)
trusblock@i-l9ptvup7:~$ bitcoin-cli gettransaction 2b8e798955ec67684f70688a0b3a55b1b5bc77f3ebbde27e2657a8c7b25fbe33
{
"amount": 0.00000000,
"fee": -0.00007480,
"confirmations": 0,
"trusted": true,
"txid": "2b8e798955ec67684f70688a0b3a55b1b5bc77f3ebbde27e2657a8c7b25fbe33",
"walletconflicts": [
],
"time": 1477814150,
"timereceived": 1477814150,
"bip125-replaceable": "no",
"details": [
{
"account": "",
"address": "msdg9VhoizVq6a7ZtDz6CJCsipZkmUeJog",
"category": "send",
"amount": -1.00000000,
"label": "",
"vout": 1,
"fee": -0.00007480,
"abandoned": false
},
{
"account": "",
"address": "msdg9VhoizVq6a7ZtDz6CJCsipZkmUeJog",
"category": "receive",
"amount": 1.00000000,
"label": "",
"vout": 1
}
],
"hex": "0100000002e1f842104186ea2e83c11ae4477aa746765137634b3e73b07c847fd69df2d0d1000000006b483045022100b72e0bab025ce4e3fc76c5791be665696b0cf0338339744ecc62433c0d4dad25022004b59af813befaa55bc908cb23d1dde3551724139c4768f5ce40e2c585f25380012103147f3dfdd9ac25984e5ebbe79662e6b1764ab329733d7b5539954f6faa5a8f01feffffffe1f842104186ea2e83c11ae4477aa746765137634b3e73b07c847fd69df2d0d1010000006a47304402201394c1f9ce61c811a06342401ad2d8ca1c8bce2b657a3737eef5593226fe73a002205e13fbe89d1bac06423a90bdc9b12107b10d132fc8a983afc77507859935c2610121029dd81b414c863afc11b6ed280cd80cfff4bd9cf94112962311b4106f16f17d13feffffff025c51f502000000001976a914df512101cf019893c5f8a6abca8c4eb438268fc088ac00e1f505000000001976a91484e6f11c291c1c8c5843706a89b74a207793f95788ac70000000"
}
交易被首次确认时产生的回调返回 txid 交易记录信息:
trusblock@i-l9ptvup7:~$ bitcoin-cli gettransaction 2b8e798955ec67684f70688a0b3a55b1b5bc77f3ebbde27e2657a8c7b25fbe33
{
"amount": 0.00000000,
"fee": -0.00007480,
"confirmations": 1,
"blockhash": "384ec9a4e6a634cc8c11bae26c2278cb607162333403a39329b5d465f3170f3f",
"blockindex": 1,
"blocktime": 1477814320,
"txid": "2b8e798955ec67684f70688a0b3a55b1b5bc77f3ebbde27e2657a8c7b25fbe33",
"walletconflicts": [
],
"time": 1477814150,
"timereceived": 1477814150,
"bip125-replaceable": "no",
"details": [
{
"account": "",
"address": "msdg9VhoizVq6a7ZtDz6CJCsipZkmUeJog",
"category": "send",
"amount": -1.00000000,
"label": "",
"vout": 1,
"fee": -0.00007480,
"abandoned": false
},
{
"account": "",
"address": "msdg9VhoizVq6a7ZtDz6CJCsipZkmUeJog",
"category": "receive",
"amount": 1.00000000,
"label": "",
"vout": 1
}
],
"hex": "0100000002e1f842104186ea2e83c11ae4477aa746765137634b3e73b07c847fd69df2d0d1000000006b483045022100b72e0bab025ce4e3fc76c5791be665696b0cf0338339744ecc62433c0d4dad25022004b59af813befaa55bc908cb23d1dde3551724139c4768f5ce40e2c585f25380012103147f3dfdd9ac25984e5ebbe79662e6b1764ab329733d7b5539954f6faa5a8f01feffffffe1f842104186ea2e83c11ae4477aa746765137634b3e73b07c847fd69df2d0d1010000006a47304402201394c1f9ce61c811a06342401ad2d8ca1c8bce2b657a3737eef5593226fe73a002205e13fbe89d1bac06423a90bdc9b12107b10d132fc8a983afc77507859935c2610121029dd81b414c863afc11b6ed280cd80cfff4bd9cf94112962311b4106f16f17d13feffffff025c51f502000000001976a914df512101cf019893c5f8a6abca8c4eb438268fc088ac00e1f505000000001976a91484e6f11c291c1c8c5843706a89b74a207793f95788ac70000000"
}
综上根据 wallet notify 返回的 txid 获取的交易记录信息。当交易记录为确认时,交易信息中包含 "generated": true ;而当钱包中交易产生的 wallet notify 回调中没有该属性。
总结
所以为了在数据库中写入充值记录,还是得解析 wallet notify 回调返回的 txid 分析交易记录信息。而不是根据返回的 txid 查询数据库中的提现记录来判断是否要添加充值记录。
最初充值记录被写入数据库时,由于这笔交易只是首次被确认,那么其在数据库中被记录的状态也是非 confirmed ,最终状态被标记为 confirmed 的条件为:确认次数大于或等于 bitcoin.conf 配置文件中的 minconf 属性设置的次数。