Closed maxgmer closed 3 months ago
Here is the decoded TX that fails to be broadcast (output value is weird btw, why does it have "n" postfix?):
{
version: 2,
vin: [
{
txid: 'fd13e6e779960e0ba56405928524d1077575568a58b8e123275f11cb8630a816',
vout: 0,
scriptSig: [],
sequence: 'fffffffd',
witness: [Array]
}
],
vout: [
{
value: 1000n,
scriptPubKey: '5120b32ce90751de8b076dc9c8f6d46f967abe6cc7a4e97c452ff17444bb60c5890b'
}
],
locktime: 0
}
And the tx hex:
0200000000010116a83086cb115f2723e1b8588a56757507d12485920564a50b0e9679e7e613fd0000000000fdffffff01e803000000000000225120b32ce90751de8b076dc9c8f6d46f967abe6cc7a4e97c452ff17444bb60c5890b0140fd7c487bc6d19245b47f9b08018d978815b97b3cfd110ec9f64daaddf13a8ed1ea8e36730c9dc4713b584b5ca004a1133423a8f83027ab7924c4ff8522e3211000000000
I think the problem may be here with txInput.vout
:
Signer.taproot.sign(taprootPk, txData, txInput.vout)
The index value should be the index of the input being signed, so like this:
for (let i = 0; i < txData.vin.length; i++) {
txData.vin[i].witness = [
Signer.taproot.sign(taprootPk, txData, i),
];
}
Try that change and let me know if it works.
p.s the n
notes a BigInt type. They are a relatively new type in javascript.
@cmdruid fixed this one, but the error is still there, unfortunately :( something else is also wrong
New TX Hash after providing the correct input indices: 020000000001010449081422de6fda2d995662ab51909a3a45bf422bcf47b40af047c94d467b360000000000fdffffff01e803000000000000225120b32ce90751de8b076dc9c8f6d46f967abe6cc7a4e97c452ff17444bb60c5890b01407515e29ca068577bc36ff4325aeb264a39298680af8400919a83f8b73651c1789d702249ff4a4c0add48b71eb67153d978116997325b4281ab6d1353faf1629200000000
Where are you getting the keys from?
You may want to try skipping this part:
const [taprootPk] = Tap.getSecKey(pk);
const [taprootPub] = Tap.getPubKey(pub);
This step adds an empty tweak to each key in your key-pair, which obfuscates the keys for privacy.
However it is not necessary and not all wallets bother to do this step, so you may want to try omitting it and signing with the keys you have directly.
@cmdruid I tried skipping tweaking, but no luck, got an error. I generate the keys myself, then tweak them, then give the taproot address to the user. Then somewhere in the future the user funds the taproot address and I invoke this problematic sending method (I invoke it with NOT tweaked private key and the method tweaks the key inside it to get access to the taproot address the user has funded).
Also, so that you don't have to waste time doing guesses, I created this minimal example with all the method inputs, how I generate the keys,mbefore I invoke the method etc.: https://pastebin.com/qH73NDqC#google_vignette
Do you end up getting the same tweaked key-pair in both cases? Does the tweaked public key, when encoded as an address, match the address of the utxo being spent?
@cmdruid Yes, the same tweaked key-pair in both cases 😢
UTXO address matches as well, yes, I re-verify UTXO data for the address being spent doing this request:
GET https://blockstream.info/testnet/api/address/tb1pxez9u8zkzhgephpus2a3fuz7jujhpeujml32a5d4g57aj9wjdqrqh02yen/utxo
What does Signer.taproot.verify(txData, i)
not check during verification? I know wrong UTXOs could be one thing, but those are correct, what else could it miss?
Maybe it will be easier for me to debug, if I at least know what could be wrong.
@cmdruid I also can reproduce this error in keyspend.test.ts. I just removed the new wallet simulation stuff from your code, as I don't have a local node.
Then I put my private key there, my UTXO input data/output data and set the network to 'testnet'.
Then, after running the test (it runs successfully), I took the TX hex and posted it to the blockstream node like this:
curl --request POST \ --url https://blockstream.info/testnet/api/tx \ --header 'Content-Type: text/plain' \ --header 'User-Agent: insomnia/9.3.2' \ --data 020000000001010449081422de6fda2d995662ab51909a3a45bf422bcf47b40af047c94d467b360000000000fdffffff015203000000000000160014d0829aa329e5716e71b10cb17a6a33df8caf72a3014095df63eff8710b308c2f69b693cf7db731cd320c0789d5fad412a1911d1105e243efbd39d2d74cfd3dd0b9fe6b8e1e5387b92b61364c4d664b609441b984d2a000000000
The pubkey that I am decoding from the address "tb1pxez9u8zkzhgephpus2a3fuz7jujhpeujml32a5d4g57aj9wjdqrqh02yen" is the following:
36445e1c5615d190dc3c82bb14f05e972570e792dfe2aed1b5453dd915d26806
Are you signing with a private key that matches this public key?
@cmdruid Secret: c8ec44f2fd52560af4aaab3210c104d18cf5904c75288d182124c2905da69102
You can import into Unisat Testnet to see for yourself. Address is derived from public and you'll see the correct address there, meaning the private matches the public key.
Can you try this test? (Paste into keyspend.test.ts and run): https://pastebin.com/raw/vhn2YJvt
You'll see all the correct keys in the test, the UTXO used here is also correct. And the test will pass, of course.
But then, use the TX Hex and submit it to blockstream (or mempool.space). The BTC node will reject it.
Blockstream submission request:
curl --request POST \
--url https://blockstream.info/testnet/api/tx \
--header 'Content-Type: text/plain' \
--data
@cmdruid okay, I realized my error, incorrect value was inputted into prevout. Sorry for disturbing :)
no problem. I'm glad that you were able to get it working!
I have a method to send sats from one p2tr address to another one. I followed this example to implement it.
The validation goes through, but when I submit the transaction to mempool.space (or blockstream, same thing), I get the following response:
sendrawtransaction RPC error: {"code":-26,"message":"non-mandatory-script-verify-flag (Invalid Schnorr signature)"}
Here is the code I send sats with (essentially the same as the example, but with many UTXOs in tx input): https://pastebin.com/hBGXNnJe