Liquid Network de Bitcoin: no se puede transmitir la transacción de emisión de PSET P2PKH utilizando elementos go

Mientras trabajaba en go-elements, he estado tratando de expandir pset_test.go implementando funciones que transmiten diferentes tipos de transacciones PSET. Desafortunadamente no puedo encontrar mucha información técnica sobre este tema.
Estoy tratando de implementar una prueba que transmite una transacción creada a partir de un PSET que emite un activo, con salidas P2PKH para el activo, l-btc (para el cambio) y la tarifa.
El código que escribí devuelve el error pset_test.go:324: Signature does not correspond to this input, que se explica por sí mismo, pero no estoy seguro de dónde me equivoqué. Agradecería alguna ayuda y también indicación de recursos técnicos que me puedan ayudar a entender un poco mejor este tema. Gracias

func TestBroadcastUnblindedIssuanceTxP2PKH(t *testing.T) {
    privkey, err := btcec.NewPrivateKey(btcec.S256())
    if err != nil {
        t.Fatal(err)
    }
    pubkey := privkey.PubKey()
    p2pkh := payment.FromPublicKey(pubkey, &network.Regtest, nil)
    address, _ := p2pkh.PubKeyHash()

    // Fund sender address.
    _, err = faucet(address)
    if err != nil {
        t.Fatal(err)
    }

    // Retrieve sender utxos.
    utxos, err := unspents(address)
    if err != nil {
        t.Fatal(err)
    }

    // The transaction will have 1 input and 3 outputs.
    txInputHash, _ := hex.DecodeString(utxos[0]["txid"].(string))
    txInputHash = bufferutil.ReverseBytes(txInputHash)
    txInputIndex := uint32(utxos[0]["vout"].(float64))
    txInput := transaction.NewTxInput(txInputHash, txInputIndex)

    lbtc, _ := hex.DecodeString(
        "5ac9f65c0efcc4775e0baec4ec03abdde22473cd3cf33c0419ca290e0751b225",
    )
    lbtc = append([]byte{0x01}, bufferutil.ReverseBytes(lbtc)...)

    changeScript := p2pkh.Script
    changeValue, _ := confidential.SatoshiToElementsValue(99999500)
    changeOutput := transaction.NewTxOutput(lbtc, changeValue[:], changeScript)

    feeScript := []byte{}
    feeValue, _ := confidential.SatoshiToElementsValue(500)
    feeOutput := transaction.NewTxOutput(lbtc, feeValue[:], feeScript)

    // Create a new pset.
    inputs := []*transaction.TxInput{txInput}
    outputs := []*transaction.TxOutput{changeOutput, feeOutput}
    p, err := New(inputs, outputs, 2, 0)
    if err != nil {
        t.Fatal(err)
    }

    updater, err := NewUpdater(p)
    if err != nil {
        t.Fatal(err)
    }

    arg := AddIssuanceArg{
        Precision: 0,
        Contract: &transaction.IssuanceContract{
            Name:      "Test",
            Ticker:    "TST",
            Version:   0,
            Precision: 0,
            Entity: transaction.IssuanceEntity{
                Domain: "test.io",
            },
        },
        AssetAmount:  1000,
        TokenAmount:  1,
        AssetAddress: address,
        TokenAddress: address,
        TokenFlag:    0,
        Net:          network.Regtest,
    }
    err = updater.AddIssuance(arg)
    if err != nil {
        t.Fatal(err)
    }

    err = updater.AddInSighashType(txscript.SigHashAll, 0)
    if err != nil {
        t.Fatal(err)
    }

    err = updater.AddInNonWitnessUtxo(updater.Data.UnsignedTx, 0)
    if err != nil {
        t.Fatal(err)
    }

    txHash := updater.Data.UnsignedTx.TxHash()
    sig, err := privkey.Sign(txHash[:])
    if err != nil {
        t.Fatal(err)
    }

    sigWithHashType := append(sig.Serialize(), byte(txscript.SigHashAll))

    // Update the pset adding the input signature script and the pubkey.
    _, err = updater.Sign(0, sigWithHashType, pubkey.SerializeCompressed(), nil, nil)
    if err != nil {
        t.Fatal(err)
    }

    valid, err := updater.Data.ValidateAllSignatures()
    if err != nil {
        t.Fatal(err)
    }
    if !valid {
        t.Fatal(errors.New("invalid signatures"))
    }

    // Finalize the partial transaction.
    p = updater.Data
    err = FinalizeAll(p)
    if err != nil {
        t.Fatal(err)
    }

    // Extract the final signed transaction from the Pset wrapper.
    finalTx, err := Extract(p)
    if err != nil {
        t.Fatal(err)
    }

    // Serialize the transaction and try to broadcast.
    txHex, err := finalTx.ToHex()
    if err != nil {
        t.Fatal(err)
    }
    _, err = broadcast(txHex)
    if err != nil {
        t.Fatal(err)
    }
}

Respuestas (1)

El error indica que no está firmando la transacción correctamente. De hecho, estás generando una firma con:

txHash := updater.Data.UnsignedTx.TxHash()
sig, err := privkey.Sign(txHash[:])

Pero el hash de la transacción actual no es lo que necesita firmar. En su lugar, debe usar HashForSignaturepara tipos de entrada heredados:

sigHash, err := updater.Data.UnsignedTx.HashForSignature(0, p2pkh.Script, txscript.SigHashAll)
if err != nil {
    t.Fatal(err)
}
sig, err := privkey.Sign(sigHash[:])

PD. Tenga en cuenta que, por el momento, el protocolo de Elements no le permite usar una entrada propiedad de una clave de secuencia de comandos heredada, por lo tanto, incluso si la transacción está bien formada, no se aceptará en mempool ni se incluirá en la cadena de bloques.