Raw SegWit TX sieht solide aus und verifiziert, wird aber abgelehnt. Benötigen Sie Hilfe, um herauszufinden, warum

Betrachten Sie die folgende als Hex ausgedrückte Transaktion:

010000000001019F92908527985B1ED14E7F6127684808523750076AB82A03A6A5A50107AC40190000000000FFFFFFFF02446C1E0000000000160014ABFA07FB45DE4B7187360F0B5E4014991666ACCB40420F0000000000160014DFFE4A0C857A04597E0DCB446DB284DD0C068E8602473044022051F99A39749B925E32BF1ED0573ED4CCFC6965F92CD0F016F644C8CF17CA57E102202FCC06C7C26A7E5F71A2DF3353BDE494561E4A6394955DE9C825D08DB573BB1D0121024B2512FFD4AA888E0E0D358083770A4A45093952EE68F3753651932849F008EC00000000

Wenn ich es in Online-Transaktionsdecoder/-validatoren wie die hier und hier einfüge , sieht alles solide aus.

Wenn Sie sie jedoch an eine öffentliche pushTX-API senden, wird ein Fehler generiert. Das Problem ist, dass die Fehlermeldungen so vage sind (z. B. "ungültige Transaktion"), dass ich nicht einmal sicher bin, wo ich suchen soll.

BlockCypher gibt den folgenden Fehler aus:

"Fehler beim Ausführen des Skripts für Eingabe 0 mit Verweis auf 1940ac0701a5a5a6032ab86a0750375208486827617f4ed11e5b98278590929f bei 0: Skript wurde NICHT erfolgreich verifiziert."

Ich habe diesen speziellen Fehler recherchiert und Leute stoßen gelegentlich darauf, wenn eine Signatur schlecht ist. Aber ich habe die Signatur unzählige Male überprüft. Es ist gültig. Wenn Sie die Transaktion hier einfügen , wird tatsächlich ein kleines Häkchen neben dem Symbol „Signiert“ angezeigt, das eine ordnungsgemäße Signatur anzeigt.

Außerdem zeigen alle Decoder die korrekten Eingänge, Ausgänge, Beträge usw. Die serialisierten Daten scheinen also nicht beschädigt oder anderweitig unlesbar zu sein.

Was könnte ich falsch machen? Ich habe den ganzen Tag damit verbracht, darüber zu recherchieren, aber ich kann nichts finden.

Mit welcher Software haben Sie diese Transaktion erstellt?

Antworten (2)

Es ist gültig. Wenn Sie die Transaktion hier einfügen, wird tatsächlich ein kleines Häkchen neben dem Symbol „Signiert“ angezeigt, das eine ordnungsgemäße Signatur anzeigt.

Es ist nicht gültig. Diese Website hat nichts validiert. Es hat nur geprüft, ob etwas im scriptWitness-Feld steht, und wenn ja, wurde es als signiert markiert. Dieses Häkchen bedeutet nicht, dass es gültig ist.

Deine Signatur ist einfach falsch. Anders kann man es nicht sagen. Wenn Sie es über meinen Bitcoin Core-Knoten ausführen, erhalten Sie

64: non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation)

Dies ist der typische Fehler aufgrund einer ungültigen Signatur.

Überprüfen Sie noch einmal, ob Sie den Seufzer korrekt erstellen. Probleme wie dieses sind normalerweise das Ergebnis einer falschen Serialisierung der Transaktion zum Signieren.

Danke, diese Fehlermeldung, die Sie bereitgestellt haben, weist mich zumindest in die richtige Richtung. Ich verwende diese .NET-Komponente namens BouncyCastle, die seit Jahren treu die Verschlüsselungs-/Signierungsarbeit für mich erledigt, absolut fehlerfrei. Ich habe die Komponente kürzlich "aufgerüstet" und die Dinge brechen irgendwie zusammen. Ich konnte Problemumgehungen für die meisten Probleme finden, aber dieses Seufzer-/Signaturproblem hat mich ratlos gemacht. Ich bleibe dran. Danke noch einmal
@FestusMartingale: Es würde wahrscheinlich helfen, wenn Sie der Frage Ihren Code hinzufügen.

Ich vermute, es wird in Programmiererkreisen als kitschig angesehen, eine Antwort auf die eigene Frage zu posten, aber in diesem Fall war mein Fehler ziemlich gefährlich, daher möchte ich die Details mit Ihnen allen teilen.

REKAPITULIEREN:

Meine Frage besagte, dass die öffentlichen „Push tx“-APIs keine brauchbaren Fehlermeldungen ausgaben, nachdem sie meine hexadezimal formatierten Rohtransaktionen abgelehnt hatten. Die Antwort von Mr. Chow deutete darauf hin, dass es sich bei dem Problem um einen Signaturfehler handelte, den er erhielt, nachdem er versucht hatte, meinen fehlerhaften TX durch seinen persönlichen Knoten zu schieben. Das hat mich in die richtige Richtung gewiesen.

Sein Vorschlag war, dass ich meinen Seufzer vielleicht nicht richtig serialisiert habe, da dies oft zu der Fehlermeldung führt, auf die er sich bezieht. Aber der Code, der diesen Sighash formuliert, funktioniert seit Jahren gut, also dachte ich, das Problem sei woanders. Tatsächlich war es so. Die Kurzgeschichte ist, dass meine Logik, die verwendet wurde, um einen öffentlichen Schlüssel von einem privaten Schlüssel abzuleiten, der ewig einwandfrei funktioniert hatte, nun nach einem Upgrade der BouncyCastle .NET-Verschlüsselungskomponente fehlschlug.

Hier ist ein Auszug meines Codes, der einen privaten Schlüssel in einen öffentlichen Schlüssel umwandelt:

public class BTCUtils2{
    public static byte[] DerivePublicKey(byte[] privKey,bool isCompr){
        ECPoint pubPt=ComputePublicECPoint(privKey);

        //byte[] xCoord = pubPt.X.ToBigInteger().ToByteArrayUnsigned(),     //2015: worked properly in with BouncyCastle 1.7.4114.6375
        //       yCoord = pubPt.Y.ToBigInteger().ToByteArrayUnsigned();

        //byte[] xCoord = pubPt.XCoord.GetEncoded(),                        //2019-07-01: upgraded to 1.8.5; generates bad data
        //       yCoord = pubPt.YCoord.GetEncoded();

        ECPublicKeyParameters publicParams = new ECPublicKeyParameters(pubPt,ECParams); //2019-07-16; proper usage of 1.8.5
        byte[] xCoord=publicParams.Q.XCoord.GetEncoded(),
               yCoord=publicParams.Q.YCoord.GetEncoded();

        if(xCoord.Length!=32 || yCoord.Length!=32){throw new ApplicationException("SANITY CHECK: Expected 32 bytes for X/Y coords");}
        byte[] bytes=new byte[isCompr?33:65];                               //public key consists of a one byte prefix (0x04=uncompress,0x02=compressed w\ y=even, 0x03=compressed w\ y=odd) prior to the payload
        if(isCompr){
            bytes[0]=((yCoord[31] & 0x01)==0)?(byte)0x02:(byte)0x03;        //compressed; set prefix based on whether Y is even or odd
            Array.Copy(xCoord,0,bytes,1,32);                                //x coord
        }
        else{
            bytes[0]=0x04;                                                  //uncompressed; set prefix to 0x04
            Array.Copy(xCoord,0,bytes,1,32);                                //x coord
            Array.Copy(yCoord,0,bytes,33,32);                               //y coord
        }
        return bytes;
    }
    private static ECPoint ComputePublicECPoint(byte[] privKey){return ECParams.G.Multiply(new BigInteger(1,privKey));}
    private static readonly ECDomainParameters  ECParams=null;
    static BTCUtils2(){
        X9ECParameters crv = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
        ECParams=new ECDomainParameters(crv.Curve, crv.G, crv.N, crv.H);
    }
}

Das Problem tritt oben auf, wo ich einen privaten Schlüssel, ausgedrückt als Byte-Array, in einen öffentlichen Schlüssel umwandle, ausgedrückt in Form seiner x/y-Koordinaten. Siehe meine Kommentare. Der Code von 2015 hat mit der Ausgabe von BouncyCastle von 2011 jahrelang gut funktioniert.

Am 01.07.2019 musste ich auf Version 1.8.5 der Hüpfburg upgraden. Der Code wird nicht mehr kompiliert. Ich dachte mir, hey, sie müssen ein paar Dinge oder was auch immer umbenannt haben, also habe ich die beiden Zeilen mit der Bezeichnung 2019-07-01 angewendet, weil ich dachte, ich würde dasselbe erreichen. GROSSER FEHLER. Ich bin mir nicht sicher, was genau diese Funktionsaufrufe zurückgeben, aber sie sind nicht die x/y-Koordinate des öffentlichen Schlüssels. Sie sind etwas ganz anderes.

Wie Sie sich vorstellen können, führt ein öffentlicher Schlüssel, der Ihrem privaten Schlüssel nicht richtig entspricht, zu allen möglichen Problemen, einschließlich fehlerhafter Bitcoin-Adressen, Signaturfehlern usw.

Heute habe ich diese schlechten Zeilen durch die mit der Bezeichnung 2019-07-16 ersetzt. Das hat funktioniert. Ich habe überprüft, ob diese Zeilen tatsächlich einen gültigen öffentlichen Schlüssel generiert haben. Transaktionen werden jetzt fehlerfrei übermittelt.

Hoffe, das ist Wert für jemanden.

Am besten,

Festus