sCryptコントラクトの開発とデバッグ中に、最も一般的で最も厄介な2つの問題は、checkSigとcheckPreimageの例外です。デバッグ中にソースコード内のエラーの特定の場所を見つけることはできますが、エラーが発生した理由と修正方法について常に混乱を感じています。今日は、これら2種類の問題をすばやく見つけて修復する方法について、すべての人に役立つことを願って、いくつかのヒントについて説明します。
sCryptボイラープレートプロジェクトには、sCryptコントラクトの特定のサンプルコードがいくつか含まれており、常に更新されているため、構成が失敗してデバッグが正常に完了できない場合があります。このプロジェクトのtokenUtxoコントラクトを例として取り上げて、これら2つのタイプの問題を見つけて解決する方法を見てみましょう。
注:この記事で使用されているsCryptプラグインのバージョンは0.4.3です。
checkPreimage例外
まず、tokenUtxo.scrypt
デバッグ起動構成を確認します(便宜上、.vscode / launch.jsonにあり、値が部分的に省略されています)。
{
"type": "scrypt",
"request": "launch",
"name": "Debug tokenUtxo",
"program": "${workspaceFolder}/contracts/tokenUtxo.scrypt",
"constructorParams": "",
"entryMethod": "split",
"entryMethodParams": "Sig(b'304402200...'), PubKey(b'0251c866a29a93b6eb51197be1e9ccdcc5e822caa69c7593905347e3ec310bebad'), 60, 22222, PubKey(b'0291e61f25a92c94103f0f4ef1f70bf3582f44cff95d497ceb3efdb945f4ce3cbe'), 40, 22222, SigHashPreimage(b'0100000028bc...')",
"txContext": {
"hex": "01000000015884e5...",
"inputSatoshis": 100000,
"opReturn": "029a77564154c6ed13ffcc387342692480e7e15f2e3ad832cf2ac6de1c3ccf28230a5a",
"inputIndex": 0
}
}
構成上デバッグスタート機能を特定split
し、entryMethodParams
パラメータが開始番号を指定し、同じ時間txContext
TXに関連するコンテキスト・パラメータを指定しました。デバッグの準備のためにvscodeでこの構成を開始すると、デバッグコンソールに次の例外が出力されたことがわかりました。
Execution failed with error SCRIPT_ERR_NULLFAIL.
Stacktrace:
/Users/hero/work/boilerplate/contracts/tokenUtxo.scrypt:14:in 'Token.split'
ここに示されている異常な場所は14行目で、コードはrequire(Tx.checkPreimage(txPreimage));
です。これから、txPreimageに問題があると推測できますが、具体的な理由は何ですか。
では前の記事、私たちは、取引の前イメージと呼ばれ、トランザクションTXによって計算することができSighash Preiamgeを導入しました。ここでTx.checkPreimage
失敗entryMethodParams
すると、値で渡されたブート構成パラメーターとtxContext
結果を使用して計算されたパラメーターに一貫性がありません。
上の図に示すように、Sighash Preimageは複数の部分で構成されています。2つのpreimageに一貫性がない場合は、一部のフィールドが異なっている必要があります。どの分野が問題ですか?次のログをもう一度見てみましょう。
----- CheckPreimage Fail Hints Begin -----
You should check the differences in detail listed below:
Fields with difference | From preimage in entry method params | From preimage calculated with tx
md5(scriptCode) | 148dd2b3fcc09d6baf15c9fcf5d961d3 | 6393778445f442466414464ee3be7cc7
Preimage calculated with tx:
0100000028bce...
----- CheckPreimage Fail Hints End -----
このジャーナルはcheckPreimage
、主に前述の2つの元の画像間の特定の違いを比較して、異常の詳細について説明します。ここに示されているのは、両方のscriptCode
MD5値が異なることです。つまり、両方の説明自体scriptCode
(ロック入力スクリプトに対応)に一貫性がありません。
最近の変更のいくつかを考えるentryMethodParams
と、おそらく問題がどこにあるかを見つけた基本的なポイント、およびtxContext
いくつかの構成パラメーターは効果がない可能性があります。だから、再計算され、更新preimage
、txContext.hex
、txContext.opReturn
他のパラメータは、デバッグは最終的に正しい結果を得ました。
checkSig例外
ある種の一般的なエラーがcheckSig
異常であり、多くの場合、署名に起因する問題が原因です。ここで、次にsenderSig
、署名の問題のエラーパラメータ値をシミュレートするように自由に変更できます。デバッグを再起動すると、次の情報が表示されます。
Execution failed with error SCRIPT_ERR_NULLFAIL.
Stacktrace:
/Users/hero/work/boilerplate/contracts/tokenUtxo.scrypt:25:in 'Token.split'
----- CheckSig Fail Hints Begin -----
You should make sure the following check points all passed:
1. private key used to sign should be corresponding to the public key 028f46cb8ec957dcda049ac549fc46d451e0095a5b6f95950bc58830a7dc21167c
2. the preimage of the tx to be signed should be 0100000028bcef7e73248aa273...
上記のプロンプト情報は、署名エラーを解決する際の主なチェックポイントをカバーしています。
1.署名の生成に使用された秘密鍵が正しいかどうかを判断します。
2.署名するtxのプリイメージ(txContextに従って自動的に計算される)が入力パラメーターと一致しているかどうかを確認します。
2つのプリイメージが同じであるかどうかを比較するには、その内部の詳細を表示するメソッドで使用SigHashPreimage
しtoJSON()
て、次のような結果を取得できます。
{
nVersion: 1,
hashPrevouts: '1029c58f269f3a1f0165149921e7a726d13bf29883f80ec3bb08c75fabaa06ad',
hashSequence: '3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044',
outpoint: {
hash: '5884e5db9de218238671572340b207ee85b628074e7e467096c267266baf77a4',
index: 0
},
scriptCode: 'fd860f5101400...',
amount: 100000,
nSequence: 4294967295,
hashOutputs: '1029c58f269f3a1f0165149921e7a726d13bf29883f80ec3bb08c75fabaa06ad',
nLocktime: 0,
sighashType: 'SigHash.ALL | SigHash.FORKID'
}
ここでの秘訣は、入力パラメーターpreimageが生成されるコードを挿入し、それを上記の例外プロンプトのpreimage出力と比較して、2つの間に考えられる違いを見つけることです。次のコードに示すように:
const {
getPreimage, SigHashPreimage, signTx } = require('scryptlib');
...
const preimage = getPreimage(tx_, token.lockingScript.toASM(), inputSatoshis, inputIndex)
const sig = signTx(tx_, privKey, token.lockingScript.toASM(), inputSatoshis)
// compare two preimages for debugging purpose
const preimage2 = new SigHashPreimage('fd860f51014001760...'); // use hex from checkSig fail hints
console.log(preimage2.toString() === preimage.toString())
console.log(preimage.toJSON())
console.log(preimage2.toJSON())
スタートアップの構成txContext
は属性preimage
計算のフィールドに影響を与えることをもう一度思い出してください。問題が発生したときに同じ比較が必要かどうかを1つずつ確認してください。