為什麼我的原始交易不規範、出現錯誤 -25 並被拒絕?
我正在嘗試將 TX 生成邏輯移植到另一種(且不受歡迎的)語言。我一直在用這種方式敲打我的頭太久了,應該走開,但是,你知道,封閉和固執。
Blockchain.info、Electrum 和 Bitcoin Core 都將我對 TX 的嘗試解碼為看起來合理的東西,例如:
{ "txid" : "49c210ae472c5b5e39447e1f6d9bc020cd0f0075cc03d919afb0857a964e1f41", "version" : 1, "locktime" : 0, "vin" : [ { "txid" : "b097384c42a3be2730db3e3720a1806c76172b6b62b2b5ee007c2c6fd295cadf", "vout" : 1, "scriptSig" : { "asm" : "30460221009f478737296e39bbcff2ef7c6f013acc25bea75941acd8573bcea83ca910018b022100e9bff518297fec344d6e7e42cabc5ec793c4be507af68210bdde803a8a2958ed0104d8f39341451e2e66a00ef010c815f1284bc5e3a187476aab319b2d127b7e219c9b9e68bff311c63474242a9baab34f7ddec05de2c45bd140a74a64621ccb42cb", "hex" : "4930460221009f478737296e39bbcff2ef7c6f013acc25bea75941acd8573bcea83ca910018b022100e9bff518297fec344d6e7e42cabc5ec793c4be507af68210bdde803a8a2958ed014104d8f39341451e2e66a00ef010c815f1284bc5e3a187476aab319b2d127b7e219c9b9e68bff311c63474242a9baab34f7ddec05de2c45bd140a74a64621ccb42cb" }, "sequence" : 4294967295 } ], "vout" : [ { "value" : 0.00439999, "n" : 0, "scriptPubKey" : { "asm" : "OP_DUP OP_HASH160 7847eb9e366653aeb8857d541236fe4fd90c57e7 OP_EQUALVERIFY OP_CHECKSIG", "hex" : "76a9147847eb9e366653aeb8857d541236fe4fd90c57e788ac", "reqSigs" : 1, "type" : "pubkeyhash", "addresses" : [ "1BxzF8rgXtuiPuSN8azdMJgryzQSWt4Uoj" ] } } ] }
嘗試在比特幣核心中發送rawtransaction,我得到“錯誤-25”。閱讀其他 StackExchange 文章和Google搜尋,可能的原因如下:
“閱讀原始碼,AcceptToMemoryPool 失敗時會返回此錯誤,但由於事務無效而失敗時不會返回此錯誤。發生這種情況時,debug.log 會發出任何資訊嗎?”
“當你的 tx 使用的是 bitcoind 從未聽說過的輸出時,你會得到那個模糊的 RPC 錯誤。” ~/.bitcoin/debug.log 中沒有出現任何內容。
嘗試使用 blockchain.info 的斜杠 pushtx 服務發送它(哦,拜託,真的沒有我可以連結到的網站的白名單嗎?),我得到“腳本導致非真實堆棧:[]”,其中暗示我在某處的簽名邏輯中犯了錯誤。
我已經瀏覽了這些:
- <http://procbits.com/2013/08/27/generating-a-bitcoin-address-with-javascript>
- <http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html>
- 需要逐步兌換原始交易範例
以及其他,包括各種 Ruby、Python、Java 和 JavaScript 實現,但我需要超過 10 個聲望才能發布超過 2 個連結。我一生都無法弄清楚我在哪裡偏離。
我知道其中的一部分已經過時了。我開始使用的私鑰(來自 Electrum)未標記為已壓縮(DecodeBase58Check 後 33 個字節,最後一個為 0x01),因此我嘗試從中提取的事務中的 publicKey 也不應該被壓縮。
我試圖從(b097384c42a3be2730db3e3720a1806c76172b6b62b2b5ee007c2c6fd295cadf,第二個輸出,又名 1 )花費的 TX 有一個輸出腳本,它是支付到公鑰雜湊(d9495c762aed3dba15eec648beb558a8a8a4d)。prevout 的完整 scriptPubKey 是:
OP_DUP OP_HASH160 d9495c762aed3dba15eec648beb55a8a43b8d1bd OP_EQUALVERIFY OP_CHECKSIG
我的私鑰,從 WIF 解碼,並通過 ecdsa::pub_from_priv()、ecdsa::pub_encode() 執行,與該值匹配。
似乎在將雜湊簽名到簽名之前對正確的內容進行雜湊處理將是困難的部分。從 ecdsa::Sign() 出來後,我將 0x01 附加到簽名中。在簽署 TX 之前,它會附加 01000000。scriptSig(我正在建構的 TX 輸入中的腳本)在簽名之前是“OP_DUP、OP_HASH160、PUSHDATA、比特幣地址(公鑰雜湊)、OP_EQUALVERIFY、OP_CHECKSIG”,然後它成為 sig 和 pubKey 的 varstr ,並且解碼為看起來合理的字節碼:
腳本簽名:
0: OP_PUSHDATA 0x304602210094c538663c149f40929bb787d6174104a694181d063943a745e558b17d09e276022100b1812105ea6d7a8206c9019303a6459a9a2b2524b364debe69405b5d8b90c6c301 74: OP_PUSHDATA 0x04d8f39341451e2e66a00ef010c815f1284bc5e3a187476aab319b2d127b7e219c9b9e68bff311c63474242a9baab34f7ddec05de2c45bd140a74a64621ccb42cb
腳本公鑰:
0: OP_DUP 1: OP_HASH160 2: OP_PUSHDATA 0x7847eb9e366653aeb8857d541236fe4fd90c57e7 23: OP_EQUALVERIFY 24: OP_CHECKSIG
使用舊的 scriptPubKey 作為 scriptSig 是近似的,並假設一個簡單的付費簽名,而不是實際從正在繪製的 TX 中提取確切的 scriptPubKey,但在這個簡單的情況下,它們似乎確實匹配。
這是原始的(錯誤的?)簽名的 TX:
0100000001dfca95d26f2c7c00eeb5b2626b2b17766c80a120373edb3027bea3424c3897b0010000008b48304502202647239b48610693967a24c7c976f0df903891113c56f50b6e3368c3f73eefb0022100e372ab8bf76ab35cba1ce6c1890fb6b27bb4d6d54f080180b46a6ecc2ae09248014104d8f39341451e2e66a00ef010c815f1284bc5e3a187476aab319b2d127b7e219c9b9e68bff311c63474242a9baab34f7ddec05de2c45bd140a74a64621ccb42cbffffffff01c0b60600000000001976a9147847eb9e366653aeb8857d541236fe4fd90c57e788ac00000000
這是程式碼:
<https://gist.github.com/scrottie/15f2fca963d164306dcb>
PrivateKey 應要求提供(那裡有 1 美元)。
如果有人能夠傾倒它並找出我哪裡出錯了,我將不勝感激。
%&@!
通過此更改修復它:
$privateKey = $privateKey->as_hex(); $privateKey =~ s{^0x}{} or die; warn sprintf "doing: python sig.py '%s' '%s'\n", $privateKey, to_hex($s256); open my $python, '-|', 'python', 'sig.py', $privateKey, to_hex($s256) or die $!; my $sig = readline $python; warn "python says for sig: $sig\n"; $sig =~ s{[^0-9a-fA-F]}{}g; $sig = from_hex($sig);
並將此文件添加為 sig.py:
import ecdsa import ecdsa.der import ecdsa.util import sys privateKey = sys.argv[1] s256 = sys.argv[2] # print("privateKey len: "); print(len(privateKey.decode('hex'))) # print(privateKey) # print("s256 len: "); print(len(s256.decode('hex'))) # print(s256) sk = ecdsa.SigningKey.from_string(privateKey.decode('hex'), curve=ecdsa.SECP256k1) sig = sk.sign_digest(s256.decode('hex'), sigencode=ecdsa.util.sigencode_der) + '\01' # 01 is hashtype print sig.encode('hex')
我是新來的,我顯然是在自欺欺人。我無法讓與 openssl 介面的 CPAN 上的模組工作,所以我有一個 EC 庫選項,它是用純 Perl 編寫的。這顯然有問題,即使它的單元測試通過了。或者我用錯了。
這導致輸出使<https://blockchain.info/pushtx>說“交易已送出”。然後硬幣移動了。
感謝所有停下來給這個眼球的人。我欠你一杯啤酒。我會嘗試用非常非常好的評論和文件來推動它。
抱歉,我不使用 perl 語言,也沒有安裝 perl 環境來調試您的程式碼
我沒有看到第 13 步,您必須將 01000000 = SIGHASH_ALL 附加到您在 makeRawTransaction 方法中登錄的數據中