Segregated-Witness

原始 SegWit TX 看起來很可靠並經過驗證,但被拒絕了。需要幫助找出原因

  • July 17, 2019

考慮以下以十六進製表示的事務:

010000000001019F92908527985B1ED14E7F6127684808523750076AB82A03A6A5A50107AC40190000000000FFFFFFFF02446C1E0000000000160014ABFA07FB45DE4B7187360F0B5E4014991666ACCB40420F0000000000160014DFFE4A0C857A04597E0DCB446DB284DD0C068E8602473044022051F99A39749B925E32BF1ED0573ED4CCFC6965F92CD0F016F644C8CF17CA57E102202FCC06C7C26A7E5F71A2DF3353BDE494561E4A6394955DE9C825D08DB573BB1D0121024B2512FFD4AA888E0E0D358083770A4A45093952EE68F3753651932849F008EC00000000

如果我將其粘貼到此處此處的線上交易解碼器/驗證器中,一切看起來都很可靠。

但是將它們送出到任何公共 pushTX API 都會產生錯誤。問題是錯誤消息是如此模糊(例如“無效交易”)我什至不知道在哪裡看。

BlockCypher 給出以下錯誤:

“在 0 處引用 1940ac0701a5a5a6032ab86a0750375208486827617f4ed11e5b98278590929f 的輸入 0 執行腳本時出錯:腳本未成功驗證。”

我已經研究過這個特定的錯誤,當簽名不好時人們偶爾會遇到它。但我已經檢查了無數次簽名。這是有效的。事實上,在此處粘貼交易實際上會在“已簽名”圖示旁邊顯示一個小複選標記,表示正確的簽名。

此外,解碼器都顯示正確的輸入、輸出、數量等。因此,序列化的數據似乎沒有損壞或不可讀。

我可能做錯了什麼?我花了一整天的時間研究它,但什麼也想不出來。

這是有效的。事實上,在此處粘貼交易實際上會在“已簽名”圖示旁邊顯示一個小複選標記,表示正確的簽名。

這是無效的。該網站沒有驗證任何內容。它只是檢查 scriptWitness 欄位中是否有內容,如果有,則將其標記為已簽名。該複選標記並不意味著它是有效的。

您的簽名完全不正確。沒有其他的說法。通過我的比特幣核心節點執行它會給出

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

這是典型的無效簽名錯誤。

仔細檢查您是否正確創建了 sighash。此類問題通常是錯誤地序列化交易以進行簽名的結果。

我懷疑在程序員圈子裡發布自己問題的答案很俗氣,但在這種情況下,我的錯誤相當危險,所以我想與大家分享細節。

回顧:

我的問題表明,在拒絕我的十六進制格式的原始交易後,公共“推送 tx”API 沒有給出可行的錯誤消息。Chow 先生的回答表明問題是簽名錯誤,他在嘗試通過他的個人節點推送我的格式錯誤的 TX 後收到該錯誤。這為我指明了正確的方向。

他的建議是,也許我沒有正確序列化我的 sighash,因為這通常會導致他引用的錯誤消息。但是製定 sighash 的程式碼多年來一直執行良好,所以我認為問題出在其他地方。確實如此。簡短的故事是,我用來從私鑰派生公鑰的邏輯一直完美無缺,但在升級 BouncyCastle .NET 加密組件後現在失敗了。

這是我將私鑰轉換為公鑰的程式碼的摘錄:

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);
   }
}

問題出現在頂部,我將私鑰(表示為字節數組)轉換為公鑰,以 x/y 座標表示。看我的評論。2015 年的程式碼在 2011 年版的 BouncyCastle 中執行良好多年。

2019-07-01 7月,我不得不升級到充氣城堡的1.8.5版本。程式碼不再編譯。我想,嘿,他們一定是重命名了一些東西或其他什麼,所以我應用了表示為 2019-07-01 的兩條線,認為我正在完成同樣的事情。重大錯誤。我不確定這些函式呼叫究竟返回了什麼,但它們不是公鑰的 x/y 座標。它們完全是另外一回事。

可以想像,擁有與您的私鑰不正確對應的公鑰會導致各種問題,包括格式錯誤的比特幣地址、簽名錯誤等。

今天,我用標記為 2019-07-16 的那些行替換了那些壞行。那成功了。我驗證了這些行實際上正在生成一個有效的公鑰。交易現在送出沒有錯誤。

希望這對某人有價值。

最好的,

非斯都

引用自:https://bitcoin.stackexchange.com/questions/89076