Skip to content
This repository has been archived by the owner on Dec 9, 2023. It is now read-only.

Transaction output duplicated by 'fungible transfer' #127

Closed
claudiosdc opened this issue Jan 15, 2021 · 6 comments
Closed

Transaction output duplicated by 'fungible transfer' #127

claudiosdc opened this issue Jan 15, 2021 · 6 comments
Assignees
Labels
bug Something isn't working
Milestone

Comments

@claudiosdc
Copy link
Contributor

I am using version 0.2.1 of RGB node to run a few basic tests to try and familiarize myself with the work that you guys are doing.

I was using the demo in /doc/demo-0.1 as a guide, and, after issuing the fungible transfer command, I noticed that the returned witness PSBT had what seemed to be a duplicate output: instead of two outputs paying 3.99789343 and 0.00030000 bitcoins respectively (as in the original PSBT passed to the fungible transfer command), it had two outputs paying the exact same amount of 3.99789343 bitcoins.

Here is the fungible transfer command that was issued:

rgb-cli fungible transfer 'rgb20:utxob1lr9rp8ygrvmq420yra6tsk6jyjkvvn5yry72dnz0wkvxl0mqe8vqu0u09n?asset=rgb1hq63xvdccglhn4mrqjvzx9gwgxfa35allc36dcz2zxcnxt75w3wqdqa6qd&amount=55' /var/lib/rgb/transf_tx.psbt /var/lib/rgb/consignment.rgb /var/lib/rgb/witness.psbt -i 536a2a6694490d1586a6bcf146e9a27a57b2665ee61fb18f9d7564f791361af5:0 -a 4945@215176c262d906f9e30c14692bdf4a9f284f6ed02ca51bca4f07592eb6301870:0

This is the contents of the transfer_tx.psbt file (base64 encoded):

cHNidP8BAHECAAAAAfUaNpH3ZHWdj7Ef5l5msld6oulG8bymhhUNSZRmKmpTAQAAAAD/////Ah9N1BcAAAAAFgAU/tnotNekXTer0RjOARcsopdnE+swdQAAAAAAABYAFHOHhjD4hd0I9Ssd9xDfvjANyfQkAAAAAAABAJACAAAAAXAYMLYuWQdPyhulLNBuTyifSt8raRQM4/kG2WLCdlEhAgAAAAD/////A0CcAAAAAAAAFgAUUBmwyRAdK+nlygxqsNdOJivGoO7cwtQXAAAAABYAFADzHLR73G3PsTxpYLOwxMwmU63mQJwAAAAAAAAWABTcp443bP2MZmFJryoi+9ST++VdXQAAAAABAR/cwtQXAAAAABYAFADzHLR73G3PsTxpYLOwxMwmU63mIgYDi4os0MxH+bn7DnOh11YLmuZYagbqbYDb9Vdt0tllgiMQpYtJpgAAAIABAACABQAAgAAiAgP6CaeE++8A2PeKxvCFrmadMjRR2zlNoIIOkjzeIYzaUxCli0mmAAAAgAEAAIALAACAACICAqnK9tKxYr3mo8BsXa8X7vvZkoShJuZUoWVEOLgmEUPuEKWLSaYAAACAAAAAgAgAAIAA

And here is its decoded (bitcoin-cli decodepsbt) contents:

{
  "tx": {
    "txid": "4b4d51df30dbfb7e70cd7de85818b4f5ff8194cf0aff63db564d78f514acc1a3",
    "hash": "4b4d51df30dbfb7e70cd7de85818b4f5ff8194cf0aff63db564d78f514acc1a3",
    "version": 2,
    "size": 113,
    "vsize": 113,
    "weight": 452,
    "locktime": 0,
    "vin": [
      {
        "txid": "536a2a6694490d1586a6bcf146e9a27a57b2665ee61fb18f9d7564f791361af5",
        "vout": 1,
        "scriptSig": {
          "asm": "",
          "hex": ""
        },
        "sequence": 4294967295
      }
    ],
    "vout": [
      {
        "value": 3.99789343,
        "n": 0,
        "scriptPubKey": {
          "asm": "0 fed9e8b4d7a45d37abd118ce01172ca2976713eb",
          "hex": "0014fed9e8b4d7a45d37abd118ce01172ca2976713eb",
          "reqSigs": 1,
          "type": "witness_v0_keyhash",
          "addresses": [
            "tb1qlmv73dxh53wn0273rr8qz9ev52tkwylteuhdl5"
          ]
        }
      },
      {
        "value": 0.00030000,
        "n": 1,
        "scriptPubKey": {
          "asm": "0 73878630f885dd08f52b1df710dfbe300dc9f424",
          "hex": "001473878630f885dd08f52b1df710dfbe300dc9f424",
          "reqSigs": 1,
          "type": "witness_v0_keyhash",
          "addresses": [
            "tb1qwwrcvv8cshws3aftrhm3pha7xqxunapyzdh7jf"
          ]
        }
      }
    ]
  },
  "unknown": {
  },
  "inputs": [
    {
      "witness_utxo": {
        "amount": 3.99819484,
        "scriptPubKey": {
          "asm": "0 00f31cb47bdc6dcfb13c6960b3b0c4cc2653ade6",
          "hex": "001400f31cb47bdc6dcfb13c6960b3b0c4cc2653ade6",
          "type": "witness_v0_keyhash",
          "address": "tb1qqre3edrmm3kulvfud9st8vxyesn98t0xrd9h4x"
        }
      },
      "non_witness_utxo": {
        "txid": "536a2a6694490d1586a6bcf146e9a27a57b2665ee61fb18f9d7564f791361af5",
        "hash": "536a2a6694490d1586a6bcf146e9a27a57b2665ee61fb18f9d7564f791361af5",
        "version": 2,
        "size": 144,
        "vsize": 144,
        "weight": 576,
        "locktime": 0,
        "vin": [
          {
            "txid": "215176c262d906f9e30c14692bdf4a9f284f6ed02ca51bca4f07592eb6301870",
            "vout": 2,
            "scriptSig": {
              "asm": "",
              "hex": ""
            },
            "sequence": 4294967295
          }
        ],
        "vout": [
          {
            "value": 0.00040000,
            "n": 0,
            "scriptPubKey": {
              "asm": "0 5019b0c9101d2be9e5ca0c6ab0d74e262bc6a0ee",
              "hex": "00145019b0c9101d2be9e5ca0c6ab0d74e262bc6a0ee",
              "reqSigs": 1,
              "type": "witness_v0_keyhash",
              "addresses": [
                "tb1q2qvmpjgsr547new2p34tp46wyc4udg8wugtpq5"
              ]
            }
          },
          {
            "value": 3.99819484,
            "n": 1,
            "scriptPubKey": {
              "asm": "0 00f31cb47bdc6dcfb13c6960b3b0c4cc2653ade6",
              "hex": "001400f31cb47bdc6dcfb13c6960b3b0c4cc2653ade6",
              "reqSigs": 1,
              "type": "witness_v0_keyhash",
              "addresses": [
                "tb1qqre3edrmm3kulvfud9st8vxyesn98t0xrd9h4x"
              ]
            }
          },
          {
            "value": 0.00040000,
            "n": 2,
            "scriptPubKey": {
              "asm": "0 dca78e376cfd8c666149af2a22fbd493fbe55d5d",
              "hex": "0014dca78e376cfd8c666149af2a22fbd493fbe55d5d",
              "reqSigs": 1,
              "type": "witness_v0_keyhash",
              "addresses": [
                "tb1qmjncudmvlkxxvc2f4u4z9775j0a72h2as5q6pz"
              ]
            }
          }
        ]
      },
      "bip32_derivs": [
        {
          "pubkey": "038b8a2cd0cc47f9b9fb0e73a1d7560b9ae6586a06ea6d80dbf5576dd2d9658223",
          "master_fingerprint": "a58b49a6",
          "path": "m/0'/1'/5'"
        }
      ]
    }
  ],
  "outputs": [
    {
      "bip32_derivs": [
        {
          "pubkey": "03fa09a784fbef00d8f78ac6f085ae669d323451db394da0820e923cde218cda53",
          "master_fingerprint": "a58b49a6",
          "path": "m/0'/1'/11'"
        }
      ]
    },
    {
      "bip32_derivs": [
        {
          "pubkey": "02a9caf6d2b162bde6a3c06c5daf17eefbd99284a126e654a1654438b8261143ee",
          "master_fingerprint": "a58b49a6",
          "path": "m/0'/0'/8'"
        }
      ]
    }
  ],
  "fee": 0.00000141
}

This is the contents of the resulting witness PSBT (base64 encoded):

cHNidP8BAHECAAAAAfUaNpH3ZHWdj7Ef5l5msld6oulG8bymhhUNSZRmKmpTAQAAAAD/////Ah9N1BcAAAAAFgAU/tnotNekXTer0RjOARcsopdnE+sfTdQXAAAAABYAFMZQDKWEyV7m2owN9qS0ENlwIVRLAAAAAAABAJACAAAAAXAYMLYuWQdPyhulLNBuTyifSt8raRQM4/kG2WLCdlEhAgAAAAD/////A0CcAAAAAAAAFgAUUBmwyRAdK+nlygxqsNdOJivGoO7cwtQXAAAAABYAFADzHLR73G3PsTxpYLOwxMwmU63mQJwAAAAAAAAWABTcp443bP2MZmFJryoi+9ST++VdXQAAAAABAR/cwtQXAAAAABYAFADzHLR73G3PsTxpYLOwxMwmU63mIgYDi4os0MxH+bn7DnOh11YLmuZYagbqbYDb9Vdt0tllgiMQpYtJpgAAAIABAACABQAAgAAiAgP6CaeE++8A2PeKxvCFrmadMjRR2zlNoIIOkjzeIYzaUxCli0mmAAAAgAEAAIALAACABv4DUkdCASED+gmnhPvvANj3isbwha5mnTI0Uds5TaCCDpI83iGM2lMAIgICqcr20rFiveajwGxdrxfu+9mShKEm5lShZUQ4uCYRQ+4QpYtJpgAAAIAAAACACAAAgAb+A1JHQgEhAqnK9tKxYr3mo8BsXa8X7vvZkoShJuZUoWVEOLgmEUPuBv4DUkdCAiDtMkT0uhzj8SwB+ee37chzV1aPiQ5/Idg0FOBYGrRidwA=

And here is its decoded (bitcoin-cli decodepsbt) contents:

{
  "tx": {
    "txid": "8344a0d070bb2fadeb9fa898493fcf144cff3d9a242e33a7bb25d33c84e8fe79",
    "hash": "8344a0d070bb2fadeb9fa898493fcf144cff3d9a242e33a7bb25d33c84e8fe79",
    "version": 2,
    "size": 113,
    "vsize": 113,
    "weight": 452,
    "locktime": 0,
    "vin": [
      {
        "txid": "536a2a6694490d1586a6bcf146e9a27a57b2665ee61fb18f9d7564f791361af5",
        "vout": 1,
        "scriptSig": {
          "asm": "",
          "hex": ""
        },
        "sequence": 4294967295
      }
    ],
    "vout": [
      {
        "value": 3.99789343,
        "n": 0,
        "scriptPubKey": {
          "asm": "0 fed9e8b4d7a45d37abd118ce01172ca2976713eb",
          "hex": "0014fed9e8b4d7a45d37abd118ce01172ca2976713eb",
          "reqSigs": 1,
          "type": "witness_v0_keyhash",
          "addresses": [
            "tb1qlmv73dxh53wn0273rr8qz9ev52tkwylteuhdl5"
          ]
        }
      },
      {
        "value": 3.99789343,
        "n": 1,
        "scriptPubKey": {
          "asm": "0 c6500ca584c95ee6da8c0df6a4b410d97021544b",
          "hex": "0014c6500ca584c95ee6da8c0df6a4b410d97021544b",
          "reqSigs": 1,
          "type": "witness_v0_keyhash",
          "addresses": [
            "tb1qcegqefvye90wdk5vphm2fdqsm9czz4ztee2u0t"
          ]
        }
      }
    ]
  },
  "unknown": {
  },
  "inputs": [
    {
      "witness_utxo": {
        "amount": 3.99819484,
        "scriptPubKey": {
          "asm": "0 00f31cb47bdc6dcfb13c6960b3b0c4cc2653ade6",
          "hex": "001400f31cb47bdc6dcfb13c6960b3b0c4cc2653ade6",
          "type": "witness_v0_keyhash",
          "address": "tb1qqre3edrmm3kulvfud9st8vxyesn98t0xrd9h4x"
        }
      },
      "non_witness_utxo": {
        "txid": "536a2a6694490d1586a6bcf146e9a27a57b2665ee61fb18f9d7564f791361af5",
        "hash": "536a2a6694490d1586a6bcf146e9a27a57b2665ee61fb18f9d7564f791361af5",
        "version": 2,
        "size": 144,
        "vsize": 144,
        "weight": 576,
        "locktime": 0,
        "vin": [
          {
            "txid": "215176c262d906f9e30c14692bdf4a9f284f6ed02ca51bca4f07592eb6301870",
            "vout": 2,
            "scriptSig": {
              "asm": "",
              "hex": ""
            },
            "sequence": 4294967295
          }
        ],
        "vout": [
          {
            "value": 0.00040000,
            "n": 0,
            "scriptPubKey": {
              "asm": "0 5019b0c9101d2be9e5ca0c6ab0d74e262bc6a0ee",
              "hex": "00145019b0c9101d2be9e5ca0c6ab0d74e262bc6a0ee",
              "reqSigs": 1,
              "type": "witness_v0_keyhash",
              "addresses": [
                "tb1q2qvmpjgsr547new2p34tp46wyc4udg8wugtpq5"
              ]
            }
          },
          {
            "value": 3.99819484,
            "n": 1,
            "scriptPubKey": {
              "asm": "0 00f31cb47bdc6dcfb13c6960b3b0c4cc2653ade6",
              "hex": "001400f31cb47bdc6dcfb13c6960b3b0c4cc2653ade6",
              "reqSigs": 1,
              "type": "witness_v0_keyhash",
              "addresses": [
                "tb1qqre3edrmm3kulvfud9st8vxyesn98t0xrd9h4x"
              ]
            }
          },
          {
            "value": 0.00040000,
            "n": 2,
            "scriptPubKey": {
              "asm": "0 dca78e376cfd8c666149af2a22fbd493fbe55d5d",
              "hex": "0014dca78e376cfd8c666149af2a22fbd493fbe55d5d",
              "reqSigs": 1,
              "type": "witness_v0_keyhash",
              "addresses": [
                "tb1qmjncudmvlkxxvc2f4u4z9775j0a72h2as5q6pz"
              ]
            }
          }
        ]
      },
      "bip32_derivs": [
        {
          "pubkey": "038b8a2cd0cc47f9b9fb0e73a1d7560b9ae6586a06ea6d80dbf5576dd2d9658223",
          "master_fingerprint": "a58b49a6",
          "path": "m/0'/1'/5'"
        }
      ]
    }
  ],
  "outputs": [
    {
      "bip32_derivs": [
        {
          "pubkey": "03fa09a784fbef00d8f78ac6f085ae669d323451db394da0820e923cde218cda53",
          "master_fingerprint": "a58b49a6",
          "path": "m/0'/1'/11'"
        }
      ],
      "unknown": {
        "fe0352474201": "03fa09a784fbef00d8f78ac6f085ae669d323451db394da0820e923cde218cda53"
      }
    },
    {
      "bip32_derivs": [
        {
          "pubkey": "02a9caf6d2b162bde6a3c06c5daf17eefbd99284a126e654a1654438b8261143ee",
          "master_fingerprint": "a58b49a6",
          "path": "m/0'/0'/8'"
        }
      ],
      "unknown": {
        "fe0352474201": "02a9caf6d2b162bde6a3c06c5daf17eefbd99284a126e654a1654438b8261143ee",
        "fe0352474202": "ed3244f4ba1ce3f12c01f9e7b7edc87357568f890e7f21d83414e0581ab46277"
      }
    }
  ],
  "fee": -3.99759202
}
@claudiosdc
Copy link
Contributor Author

I have done some investigation, and it seems that the root of this issue lies in the rust-lnpbp crate, more specifically in the commit() associated function of the Anchor structure.

The problem, for what I could see, is that the transaction output (vout) on which the tweak should be applied is being calculated in two different places using different methods.

The first place where the vout is calculated is inside the commit() associated function of the Anchor structure (as can be seen here: https://github.com/LNP-BP/rust-lnpbp/blob/e35da7d534250ac7c52ebfae45c8bd772400a7ab/src/rgb/stash/anchor.rs#L139-L154).

The second place where the vout is calculated is in the vout() method of the TxContainer structure (as can be seen here: https://github.com/LNP-BP/rust-lnpbp/blob/e35da7d534250ac7c52ebfae45c8bd772400a7ab/src/bp/dbc/tx.rs#L71-L77).

There, one can notice that the transaction fee is used in the calculation of the vout. And taking the fact that, in this particular case, the protocol_factor field of the TxContainer structure is set to the vout as calculated inside the commit() associated function of the Anchor structure (as can be seen here: https://github.com/LNP-BP/rust-lnpbp/blob/e35da7d534250ac7c52ebfae45c8bd772400a7ab/src/rgb/stash/anchor.rs#L195-L211), one can conclude that, depending on the value of the transaction fee, the two vouts will point to distinct transaction outputs. And this is exactly what happens in this specific situation.

At some point in the processing of the commit() associated function of the Anchor structure, the embed_commit() associated function of the TxCommitment structure is called (as can be seen here: https://github.com/LNP-BP/rust-lnpbp/blob/e35da7d534250ac7c52ebfae45c8bd772400a7ab/src/rgb/stash/anchor.rs#L221-L222).

Then, in the processing of the embed_commit() associated function of the TxCommitment structure, the tweaked transaction output is updated into the transaction itself. However, the transaction output that is being replaced is indexed by the vout as calculated by the vout() method of the TxContainer structure (as can be seen here: https://github.com/LNP-BP/rust-lnpbp/blob/e35da7d534250ac7c52ebfae45c8bd772400a7ab/src/bp/dbc/tx.rs#L147), while the whole processing of the tweak was done using the vout as calculated by the commit() associated function of the Anchor structure. And this is precisely what is causing the reported issue.

@dr-orlovsky dr-orlovsky added the bug Something isn't working label Jan 16, 2021
@dr-orlovsky dr-orlovsky added this to the v0.2.1 milestone Jan 16, 2021
@dr-orlovsky
Copy link
Member

dr-orlovsky commented Jan 16, 2021

Thank you very much for finding this issue and such a thorough investigation on it. @rajarshimaitra can you help me looking into possible fixes on it?

NB: We must take into an account that there are one-to-many relations between Transaction, Anchor and commitments; thus Anchor::commit returns a vec of Anchors, each of which can contain multiple commitments. That is why vout calculated twice: first we group commitments into sets per each output, and then produce anchor for each of those outputs

UPD: from my preliminary analysis the problem can be fixed by

@rajarshimaitra
Copy link
Contributor

Had a look and I have a few questions.

adding fee to id in https://github.com/LNP-BP/rust-lnpbp/blob/e35da7d534250ac7c52ebfae45c8bd772400a7ab/src/rgb/stash/anchor.rs#L139-L154

This will then make vout calculation in anchor incompatible with vout calculation in TxContainer. For each ContractId this will then calculate different vouts. I think you meant "replace" instead of "add"?

Using 0 instead of fee in https://github.com/LNP-BP/rust-lnpbp/blob/e35da7d534250ac7c52ebfae45c8bd772400a7ab/src/rgb/stash/anchor.rs#L197

This feels bandaid-y. Instead, how about we define protocol_factor properly somewhere(enum?) and use the appropriate protocol factor everywhere? We can set it to 0 for all the cases for now and the TxContainer constructor should then use the fee and protocol_factor as intended.

I will make the PR. looking for Approach ACK.

@dr-orlovsky
Copy link
Member

The problem here is the fact that at the level of transaction we do not have an access to the fee information. According to LNPBP-3 fee and protocol factor are just two additive numbers, which are modulo divided number of outputs; so
a) to fix the bug now we have to make them working correctly. If you'd like to rename them into factor1 and factor2 to remove the confusion that is totally ok
b) later in v0.3 I will do a refactoring of this part of the API, but for v0.2 branch we need a fix of this kind

@rajarshimaitra
Copy link
Contributor

rajarshimaitra commented Jan 27, 2021

Understood. Going with the quick fix for now. So fix is as below:

  • Replace ContractId with fee + protocol_factor. Keep protocol_factor as 0 for now, so vout = fee % nouts. This will make the two derivation compatible.

  • Use correct fee and protocol_factor = 0 in TxContainer construction.

Sounds good?

It will probably take some edit in the demo doc as the project has been refactored heavily. Also that rgb-cli issue I mentioned yesterday will be there. I will try to see how can I run the demo on master to check the fix.

UkolovaOlga added a commit to LNP-BP/devcalls that referenced this issue Feb 15, 2021
10.02.2021 Agenda:
RGB QA

Issues from https://github.com/orgs/rgb-org/projects/11:

1. Properly handle result from 'validate' request to Stash daemon - RGB-WG/rgb-node#132
2. Asset state transition node ID mutability
    - https://github.com/rgb-org/rgb-node/issues/133
    - RGB-WG/rgb-node#131
    - Asset transfer validation is ineffective: RGB-WG/rgb-node#130
3. Question about fungible asset known allocations semantics - RGB-WG/rgb-node#134
4. Transfer change allocation not being registered - RGB-WG/rgb-node#129
5. Transaction output duplicated by 'fungible transfer' - RGB-WG/rgb-node#127
@dr-orlovsky
Copy link
Member

Solved with RGB-WG/rgb-core#4

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants