So, then how do I easily spot this with a reasonably recent standard client?
Using QT client. 0.8.0+ works fine, probably older clients as well.
This will give you the raw tx details in hex.
This will give you json representation of a tx.
You can do your own parsing of the raw hex or you can feed the hext into decoderawtx. Either way you now have the details of your payment.
For example (tx pulled randomly from the blockchain)
getrawtransaction da38a5fa60993f96a855265e1b6986d8a13eba983edf52992dab558656f45270
01000000026b7a832578be08083147c5b5734b359b2c04c552d8dda3c0b3eef007f852d5ac01000 0008e4d4700304402202e3cc369b33adca49763d3bd2f91f090b8a86117f67bcdb32d0607a5212f 065a02207bfefc91193c23d8a9b43120541d8e9a40bd06c277f064d5dd5805b45d867f31014d410 0049763964852d711f5b230601a9cb081dd71c07d46b589305ebfa46d3f4f2e2c45f26819efe4c5 b0fa2de5af2d4c77acec8eab9f1dec1b5e70438c2f8b943de68cffffffff57a11702d068380603e e9c71d97a280d4d8ef34c46443034de3095fbbcef7ee8010000008e4d4700304402202ada2194c1 f68a6ed2e7712693c7fde823c75223319cbe38a9818503e00d613002200a34637ce86dacc835603 088b3519fb9c419c77b79b4084a554b55487f803e8e014d410004b13e7ae7f4a7a9942c3a2998c8 e427fec24cf2e3f3d3501a7c35ab951b07daaeddd621e0115d0e6291615fed8b3ef67a5a2fc7971 70db7028710d0cdb0e18cb5ffffffff02f0076606000000001976a91472e57193b8672cd0875adc 9c0264ca6fa15e3e4688acf7641800000000001976a91404157cfd60177f4fa31c7572d7f5fe14a 8f7930d88ac00000000
decoderawtx 01000000026b7a832578be08083147c5b5734b359b2c04c552d8dda3c0b3eef007f852d5ac01000 0008e4d4700304402202e3cc369b33adca49763d3bd2f91f090b8a86117f67bcdb32d0607a5212f 065a02207bfefc91193c23d8a9b43120541d8e9a40bd06c277f064d5dd5805b45d867f31014d410 0049763964852d711f5b230601a9cb081dd71c07d46b589305ebfa46d3f4f2e2c45f26819efe4c5 b0fa2de5af2d4c77acec8eab9f1dec1b5e70438c2f8b943de68cffffffff57a11702d068380603e e9c71d97a280d4d8ef34c46443034de3095fbbcef7ee8010000008e4d4700304402202ada2194c1 f68a6ed2e7712693c7fde823c75223319cbe38a9818503e00d613002200a34637ce86dacc835603 088b3519fb9c419c77b79b4084a554b55487f803e8e014d410004b13e7ae7f4a7a9942c3a2998c8 e427fec24cf2e3f3d3501a7c35ab951b07daaeddd621e0115d0e6291615fed8b3ef67a5a2fc7971 70db7028710d0cdb0e18cb5ffffffff02f0076606000000001976a91472e57193b8672cd0875adc 9c0264ca6fa15e3e4688acf7641800000000001976a91404157cfd60177f4fa31c7572d7f5fe14a 8f7930d88ac00000000
{
"txid" : "da38a5fa60993f96a855265e1b6986d8a13eba983edf52992dab558656f45270",
"version" : 1,
"locktime" : 0,
"vin" : [
{
"txid" : "acd552f807f0eeb3c0a3ddd852c5042c9b354b73b5c547310808be7825837a6b",
"vout" : 1,
"scriptSig" : {
"asm" : "304402202e3cc369b33adca49763d3bd2f91f090b8a86117f67bcdb32d0607a5212f065a02207bf efc91193c23d8a9b43120541d8e9a40bd06c277f064d5dd5805b45d867f3101 049763964852d711f5b230601a9cb081dd71c07d46b589305ebfa46d3f4f2e2c45f26819efe4c5b 0fa2de5af2d4c77acec8eab9f1dec1b5e70438c2f8b943de68c",
"hex" : "4d4700304402202e3cc369b33adca49763d3bd2f91f090b8a86117f67bcdb32d0607a5212f065a0 2207bfefc91193c23d8a9b43120541d8e9a40bd06c277f064d5dd5805b45d867f31014d41000497 63964852d711f5b230601a9cb081dd71c07d46b589305ebfa46d3f4f2e2c45f26819efe4c5b0fa2 de5af2d4c77acec8eab9f1dec1b5e70438c2f8b943de68c"
},
"sequence" : 4294967295
},
{
"txid" : "e87eefbcfb9530de343044464cf38e4d0d287ad9719cee03063868d00217a157",
"vout" : 1,
"scriptSig" : {
"asm" : "304402202ada2194c1f68a6ed2e7712693c7fde823c75223319cbe38a9818503e00d613002200a3 4637ce86dacc835603088b3519fb9c419c77b79b4084a554b55487f803e8e01 04b13e7ae7f4a7a9942c3a2998c8e427fec24cf2e3f3d3501a7c35ab951b07daaeddd621e0115d0 e6291615fed8b3ef67a5a2fc797170db7028710d0cdb0e18cb5",
"hex" : "4d4700304402202ada2194c1f68a6ed2e7712693c7fde823c75223319cbe38a9818503e00d61300 2200a34637ce86dacc835603088b3519fb9c419c77b79b4084a554b55487f803e8e014d410004b1 3e7ae7f4a7a9942c3a2998c8e427fec24cf2e3f3d3501a7c35ab951b07daaeddd621e0115d0e629 1615fed8b3ef67a5a2fc797170db7028710d0cdb0e18cb5"
},
"sequence" : 4294967295
}
],
"vout" : [
{
"value" : 1.07350000,
"n" : 0,
"scriptPubKey" : {
"asm" : "OP_DUP OP_HASH160 72e57193b8672cd0875adc9c0264ca6fa15e3e46 OP_EQUALVERIFY OP_CHECKSIG",
"hex" : "76a91472e57193b8672cd0875adc9c0264ca6fa15e3e4688ac",
"reqSigs" : 1,
"type" : "pubkeyhash",
"addresses" : [
"1BUWttqJ7gNNhqfYF8rjVpYBPj735PVhRQ"
]
}
},
{
"value" : 0.01598711,
"n" : 1,
"scriptPubKey" : {
"asm" : "OP_DUP OP_HASH160 04157cfd60177f4fa31c7572d7f5fe14a8f7930d OP_EQUALVERIFY OP_CHECKSIG",
"hex" : "76a91404157cfd60177f4fa31c7572d7f5fe14a8f7930d88ac",
"reqSigs" : 1,
"type" : "pubkeyhash",
"addresses" : [
"1NbSoCQiHQCuJc7jPn4SuNXu2xrkyvrWs"
]
}
}
]
}
These RPC call(s) can be made at the time the payment is made and stored. The bolded part is what we are interested. You can save the full output but this is the minimum information you need. Lets imagine tx da38a5fa60993f96a855265e1b6986d8a13eba983edf52992dab558656f45270 was a payment from MtGox to a customer.
The payment to the user was made using two inputs:
"txid" : "acd552f807f0eeb3c0a3ddd852c5042c9b354b73b5c547310808be7825837a6b", "vout" : 1"txid" : "e87eefbcfb9530de343044464cf38e4d0d287ad9719cee03063868d00217a157", "vout" : 1Note this is all we care about. The amount of the inputs are not needed. If these inputs are in are found in a tx to the user in a block regardless of the tx hash then the user has been paid.
So before MtGox pays the user again they need to verify that these outputs don't exist in a tx in any block since the tx was created.
How do to that. Well here are two options (there likely are more):
Method 1: Scan all tx in all blocks as blocks are received.Pro: you get realtime status of mutated txs.
Cons: it is probably more resource intensive then it is worth given the low rate that tx should be mutated in normal operation.
When bitcoind reports a block has been received, you pull the block details
You can then parse all the raw tx in the block using getrawtransaction and decoderawtransaction. If any of the tx have the same inputs from your payment tx then the tx is confirmed, update your records to reflect that the hash is changed, and also flag the tx as having been "modified" after being sent.
Personally I wouldn't even do this because in my experience mutated tx are insanely rare under normal conditions but it is an option.
Method 2: Just flag tx which don't confirm. Don't send repayment until you validate flagged transactions.At block time simply update tx based on tx hash. This should get 99.9% of your tx. Tx normally are not going to be modified. Note this will never give false positives. There is no risk in doing this.
Now some tx hashes may be modified but they should be rare so we can handle them in batches at periodic intervals (say every 24 hours). Tx which don't confirm in some expected period of time (say 60 blocks) are flagged.
Once a day do a "missing tx" check.
1) generate a list of blocks since the last time the check was run.
2) pull the tx hashes from the blocks.
3) get the raw tx and decode (either using internal process or using the decoderawtx RPC).
4) For each decoded raw tx compare the inputs (txin_hash and txin_index) of the decoded block tx to your list of "missing tx".
If you get a match the tx is not missing. "Someone" likely the user mutated the hash. So update your records to reflect the correct tx_hash, block#, and confirmation status. Like in method #1 I would also flag the tx that it was mutated.
Matching based on raw tx is slower than tx hash. Since most tx are going to have same tx hash this is why I prefer to do this as a periodic job. You can also run this job on a different server so as to not impact the load on the main tx server.
The advantage of flagging tx (by eithe rmethod) is it provides you the ability to report on how often this is occurring and with which users. If you have 10,000 tx in a month and only have 20 "missing" txs and of those 20, 18 involve a single user, you might want to drop that user, especially if he keeps reporting to customer support that he isn't "getting paid".