Monday, April 22, 2024
HomeBitcoinSignal lightning channel creation PSBT with Golang

Signal lightning channel creation PSBT with Golang


I am making an attempt to open a channel on regtest with LND v0.13.0-beta.rc3 utilizing their PSBT workflow to permit for distant signing.

I’ve performed the next steps:

  1. I create a regtest pockets utilizing the BIP39 mnemonic bronze execute spirit sense rack this repeat entry crash practice elder goal lease acquire limb view gossip say finest desert uncover jaguar exhaust card
  2. I import the prolonged public key for my account into LND
    seed, err := bip39.MnemonicToByteArray(pockets.Mnemonic, true)
    if err != nil {
        return err
    }

    // Generate a brand new grasp node utilizing the seed.
    prvkey, err := hdkeychain.NewMaster(seed, &chaincfg.RegressionNetParams)
    if err != nil {
        return err
    }

    for i := 0; i < 3; i++ {
        prvkey, err = prvkey.Derive(hdkeychain.HardenedKeyStart)
        if err != nil {
            return err
        }
    }

    key, err := prvkey.Neuter()
    if err != nil {
        return err
    }

    importReq := &walletrpc.ImportAccountRequest{
        Title:                 "check",
        ExtendedPublicKey:    key.String(),
        MasterKeyFingerprint: writeUint32(prvkey.ParentFingerprint()),
        AddressType:          1,
        DryRun:               false,
    }
    res, err := m.shopper.ImportAccount(ctx, importReq)
lnd@alice:/$ lncli pockets accounts listing
{
    "accounts": [
        {
            "name": "default",
            "address_type": "HYBRID_NESTED_WITNESS_PUBKEY_HASH",
            "extended_public_key": "upub5Dbp2w1Q7VPuhHQhPtq6rJj7wy8bbEdjFyn1TuHg6MmoSTvR3biPji1nvMRAeoyskhBUBNGGFhzUBm5KQ51M24nKcoxQ7ioFuFeyuiWqk8p",
            "master_key_fingerprint": null,
            "derivation_path": "m/49'/0'/0'",
            "external_key_count": 0,
            "internal_key_count": 0,
            "watch_only": false
        },
        {
            "name": "default",
            "address_type": "WITNESS_PUBKEY_HASH",
            "extended_public_key": "vpub5YyjQMoehZ9g6gu4sQ1VdBTwwMfgfBsPzViqWjMACu1r1JcFkky2PRyYmrGNtgQZh2BY9ZprnRoUjpFm2cx9mPiJ9NhZZ7uCZgQ8x4UNay5",
            "master_key_fingerprint": null,
            "derivation_path": "m/84'/0'/0'",
            "external_key_count": 1,
            "internal_key_count": 3,
            "watch_only": false
        },
        {
            "name": "test",
            "address_type": "WITNESS_PUBKEY_HASH",
            "extended_public_key": "tpubDDMrn46y7HdxK2AHN1anVxj8gSiYLXtmZ4Jyn1Q9Va7AZt5XBdbQ8CUms5NRv6eXBGA8FsJTcEk6h3Wihb49BYMxMqM6k83FWYCpAFLN7Rh",
            "master_key_fingerprint": null,
            "derivation_path": "m/84'/0'/0'",
            "external_key_count": 2,
            "internal_key_count": 35,
            "watch_only": true
        }
    ]
}
  1. I name the LND gRPC endpoint Lighting.OpenChannel with a Psbt FundingShim and obtain the empty PSBT
  2. I name WalletKit.FundPsbt to fund the PSBT with the check account and get the next PSBT
cHNidP8BAH0CAAAAAf1dlbtrkfmWZasLXxXBEOZbqL5bNT7xONtdc2zTvSRdAAAAAAD/////AoAaBgAAAAAAIgAgLXNsa/AXkklm/LtR6cRgyY0R3TjzCv4OpA0zK7Rc0pNmqAoAAAAAABYAFJrmQkFPaRSt6hfN8U4KFByZXIw3AAAAAAABAN4BAAAAAAEBvvrMn8zVi8D0+0mKi3TGtP8OltDfymQNbfrF1PvEvMIBAAAAAP////8C4MgQAAAAAAAWABQKYpfN3bKI+eLmUec/pPAHC5aUB4Gc1QUAAAAAFgAUOk/UwylhTSOS9zMFLinyDOpn3m4CRzBEAiB11J75wXdm8VggN5MAD2FfG6oRVwAOge+V7XVC3cv34QIgE11HHRZuFZnqaTwSsgycVSHemWoC4GjgXQcO3+odgBcBIQNThPBjoshiGPI00vjOkMJ2pFgb6cvt4qOnOn2FQhDeRgAAAAABAR/gyBAAAAAAABYAFApil83dsoj54uZR5z+k8AcLlpQHAQMEAQAAACIGAzR2EGePj6pLqU6hqkgFrayXL+8s6cj42Q118v0X0CYcGAAAAABUAACAAAAAgAAAAIAAAAAAAAAAAAAAAA==

which bitcoin-cli decodes to

{
  "tx": {
    "txid": "23cec773304f28bb78fdd88b4ad31e3b5f4331b83b7106831f1a4e182e3449a4",
    "hash": "23cec773304f28bb78fdd88b4ad31e3b5f4331b83b7106831f1a4e182e3449a4",
    "model": 2,
    "measurement": 125,
    "vsize": 125,
    "weight": 500,
    "locktime": 0,
    "vin": [
      {
        "txid": "5d24bdd36c735ddb38f13e355bbea85be610c1155f0bab6596f9916bbb955dfd",
        "vout": 0,
        "scriptSig": {
          "asm": "",
          "hex": ""
        },
        "sequence": 4294967295
      }
    ],
    "vout": [
      {
        "value": 0.00400000,
        "n": 0,
        "scriptPubKey": {
          "asm": "0 e9c4eaee376e5961d61e73fa5e855f224b31037bab32de63ec83ced969c4dcf5",
          "hex": "0020e9c4eaee376e5961d61e73fa5e855f224b31037bab32de63ec83ced969c4dcf5",
          "reqSigs": 1,
          "type": "witness_v0_scripthash",
          "addresses": [
            "bc1qa8zw4m3hdevkr4s7w0a9ap2lyf9nzqmm4veduclvs08dj6wymn6sgq85mn"
          ]
        }
      },
      {
        "worth": 0.00698470,
        "n": 1,
        "scriptPubKey": {
          "asm": "0 aafc3223cb003a5077badd7af66cab8dd0576976",
          "hex": "0014aafc3223cb003a5077badd7af66cab8dd0576976",
          "reqSigs": 1,
          "sort": "witness_v0_keyhash",
          "addresses": [
            "bc1q4t7ryg7tqqa9qaa6m4a0vm9t3hg9w6tkk89wnz"
          ]
        }
      }
    ]
  },
  "unknown": {
  },
  "inputs": [
    {
      "witness_utxo": {
        "amount": 0.01100000,
        "scriptPubKey": {
          "asm": "0 0a6297cdddb288f9e2e651e73fa4f0070b969407",
          "hex": "00140a6297cdddb288f9e2e651e73fa4f0070b969407",
          "type": "witness_v0_keyhash",
          "address": "bc1qpf3f0nwak2y0nchx28nnlf8squ9ed9q88sfrrr"
        }
      },
      "non_witness_utxo": {
        "txid": "5d24bdd36c735ddb38f13e355bbea85be610c1155f0bab6596f9916bbb955dfd",
        "hash": "4b84437691dbc3ed4c4e6cb1946ebefe7f26147d6d42f25aea73582f20049800",
        "version": 1,
        "size": 222,
        "vsize": 141,
        "weight": 561,
        "locktime": 0,
        "vin": [
          {
            "txid": "c2bcc4fbd4c5fa6d0d64cadfd0960effb4c6748b8a49fbf4c08bd5cc9fccfabe",
            "vout": 1,
            "scriptSig": {
              "asm": "",
              "hex": ""
            },
            "txinwitness": [
              "3044022075d49ef9c17766f158203793000f615f1baa1157000e81ef95ed7542ddcbf7e10220135d471d166e1599ea693c12b20c9c5521de996a02e068e05d070edfea1d801701",
              "035384f063a2c86218f234d2f8ce90c276a4581be9cbede2a3a73a7d854210de46"
            ],
            "sequence": 4294967295
          }
        ],
        "vout": [
          {
            "value": 0.01100000,
            "n": 0,
            "scriptPubKey": {
              "asm": "0 0a6297cdddb288f9e2e651e73fa4f0070b969407",
              "hex": "00140a6297cdddb288f9e2e651e73fa4f0070b969407",
              "reqSigs": 1,
              "type": "witness_v0_keyhash",
              "addresses": [
                "bc1qpf3f0nwak2y0nchx28nnlf8squ9ed9q88sfrrr"
              ]
            }
          },
          {
            "worth": 0.97885313,
            "n": 1,
            "scriptPubKey": {
              "asm": "0 3a4fd4c329614d2392f733052e29f20cea67de6e",
              "hex": "00143a4fd4c329614d2392f733052e29f20cea67de6e",
              "reqSigs": 1,
              "sort": "witness_v0_keyhash",
              "addresses": [
                "bc1q8f8afsefv9xj8yhhxvzju20jpn4x0hnwgnx7ny"
              ]
            }
          }
        ]
      },
      "sighash": "ALL",
      "bip32_derivs": [
        {
          "pubkey": "03347610678f8faa4ba94ea1aa4805adac972fef2ce9c8f8d90d75f2fd17d0261c",
          "master_fingerprint": "00000000",
          "path": "m/84'/0'/0'/0/0"
        }
      ]
    }
  ],
  "outputs": [
    {
    },
    {
    }
  ],
  "payment": 0.00001530
}
  1. I try to signal the transaction utilizing code tailored from this SO thread.
func (w *RemoteWallet) FinalizePsbt(psbtBytes []byte) ([]byte, error) {
    reader := bytes.NewReader(psbtBytes)
    packet, err := psbt.NewFromRawBytes(reader, false)
    if err != nil {
        return nil, err
    }

    // Load the prolonged personal key.
    seed, err := bip39.MnemonicToByteArray(w.Mnemonic, true)
    if err != nil {
        return nil, err
    }

    // Generate a brand new grasp node utilizing the seed.
    bip32Key, err := hdkeychain.NewMaster(seed, &chaincfg.RegressionNetParams)
    if err != nil {
        return nil, err
    }
    log.Printf("key1 %s", bip32Key.String())

    for i := 0; i < 3; i++ {
        bip32Key, err = bip32Key.Derive(hdkeychain.HardenedKeyStart)
        if err != nil {
            return nil, err
        }
    }

    key, err := bip32Key.Neuter()
    if err != nil {
        return nil, err
    }
    log.Printf("depth %d", key.Depth())
    log.Printf("key2 %s", key.String())

    log.Println("FinalizePsbt Accomplished Loading")

    for idx, enter := vary packet.Inputs {
        // Derivation path must be learn from PSBT.
        // Observe: We ignore checking the fingerprint, and so on.
        path := enter.Bip32Derivation[0]
        log.Printf("enter path: %v", path.Bip32Path)
        inputKey := bip32Key
        for _, d := vary path.Bip32Path {
            inputKey, _ = inputKey.Derive(d)
        }
        pubkey, err := inputKey.Neuter()
        if err != nil {
            return nil, err
        }
        log.Printf("depth %d", pubkey.Depth())
        log.Printf("enter key %s", pubkey.String())

        pubKey, err := bip32Key.ECPubKey()
        if err != nil {
            return nil, err
        }
        privKey, err := bip32Key.ECPrivKey()
        if err != nil {
            return nil, err
        }

        log.Printf("SighashType: %v", enter.SighashType)
        log.Printf("Witness script: %v", enter.WitnessScript)

        sigHashes := txscript.NewTxSigHashes(packet.UnsignedTx)

        sig, err := txscript.RawTxInWitnessSignature(packet.UnsignedTx, sigHashes, idx,
            enter.WitnessUtxo.Worth, enter.WitnessUtxo.PkScript,
            txscript.SigHashAll, privKey)

        if err != nil {
            return nil, err
        }
        log.Println("Signing enter")

        // Use the Updater so as to add the signature to the enter.
        u, err := psbt.NewUpdater(packet)
        if err != nil {
            return nil, err
        }
        success, err := u.Signal(idx, sig, pubKey.SerializeCompressed(), nil, enter.WitnessScript)
        if err != nil {
            return nil, err
        }
        if success != psbt.SignSuccesful {
            return nil, fmt.Errorf("couldn't sucessfully signal psbt")
        }

        log.Println("Signed enter")
    }
    // Finalize PSBT.
    err = psbt.Finalize(packet, 0)
    if err != nil {
        return nil, err
    }

    tx, err := psbt.Extract(packet)
    if err != nil {
        return nil, err
    }

    var buf bytes.Buffer
    err = tx.Serialize(&buf)
    return buf.Bytes(), err
}

This outputs

2021/06/28 14:36:35 key1 tprv8ZgxMBicQKsPeHPJRNuvXzDo2U86CLouVfExiLeiTrcffR9aDRC3zMLTPHohQhEFSQNvCAmVeX7SXGS5te7pfdLXjWHsaaLGL3gsktdGziG
2021/06/28 14:36:35 depth 3
2021/06/28 14:36:35 key2 tpubDDMrn46y7HdxK2AHN1anVxj8gSiYLXtmZ4Jyn1Q9Va7AZt5XBdbQ8CUms5NRv6eXBGA8FsJTcEk6h3Wihb49BYMxMqM6k83FWYCpAFLN7Rh
2021/06/28 14:36:35 FinalizePsbt Accomplished Loading
2021/06/28 14:36:35 enter path: [2147483732 2147483648 2147483648 0 0]
2021/06/28 14:36:35 depth 5
2021/06/28 14:36:35 enter key tpubDFuWC8gxvpmEMQMhsr5vhE1FviMyPKpPTi2dBBMJ9sBvacjeuFbnK6JWULL25e8mXRoTRjVAe1e9GqmiynAFUwKrqKnRVC46bz4ssBRHxmW
2021/06/28 14:36:35 SighashType: 1
2021/06/28 14:36:35 Witness script: []
2021/06/28 14:36:35 Signing enter

earlier than crashing with the error Signature doesn't correspond to this enter.

That is my first time working with PSBTs, so I am unsure what I am doing. I have been enjoying round with numerous elements of the FinalizePsbt func, however with none good sources, it has been a guessing recreation.

If I missed any vital information, please let me know. Any assistance is appreciated!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments