Durante el desarrollo y la depuración del contrato sCrypt, los dos problemas más comunes y problemáticos son las excepciones checkSig y checkPreimage. Aunque podemos localizar la ubicación específica del error en el código fuente durante la depuración, siempre nos sentimos confundidos acerca de por qué falló y cómo solucionarlo. Hoy vamos a hablar sobre algunos consejos sobre cómo localizar y reparar rápidamente estos dos tipos de problemas, con la esperanza de que sean de utilidad para todos.
El proyecto modelo sCrypt contiene algunos códigos de muestra específicos del contrato sCrypt y se actualiza constantemente, por lo que a veces puede encontrar una situación en la que la configuración falla y la depuración no se puede completar normalmente. Tomemos el contrato tokenUtxo de este proyecto como ejemplo para ver cómo localizar y resolver estos dos tipos de problemas.
Nota: La versión del complemento sCrypt utilizada en este artículo es 0.4.3 .
checkPreimage excepción
Primero, mire tokenUtxo.scrypt
la configuración de inicio de depuración (ubicada .vscode / launch.json para mayor comodidad, vea los valores parcialmente omitidos):
{
"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
}
}
La configuración de depuración anterior especifica la función de inicio split
y entryMethodParams
los parámetros especifican el número de inicio; el mismo txContext
parámetro de contexto especificado de tiempo relacionado con tx. Cuando comenzamos esta configuración en vscode para prepararnos para la depuración, encontramos que la siguiente excepción se mostraba en la Consola de depuración:
Execution failed with error SCRIPT_ERR_NULLFAIL.
Stacktrace:
/Users/hero/work/boilerplate/contracts/tokenUtxo.scrypt:14:in 'Token.split'
La ubicación anormal que se muestra aquí está en la línea 14, y el código es require(Tx.checkPreimage(txPreimage));
A partir de esto, se puede inferir que hay un problema con txPreimage, pero ¿cuál es la razón específica?
En el artículo anterior , presentamos Sighash Preiamge, que se denomina imagen previa de la transacción y se puede calcular mediante la transacción tx. Aquí Tx.checkPreimage
falla, los parámetros de configuración de arranque entryMethodParams
pasados en el valor y el uso de txContext
los parámetros calculados del resultado son inconsistentes.
Como se muestra en la figura anterior, Sighash Preimage se compone de varias partes. Si las dos preimágenes son inconsistentes, algunos de los campos deben ser diferentes. ¿Qué campo es el problema? Veamos nuevamente el siguiente registro:
----- 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 -----
Esta revista nos proporciona checkPreimage
más detalles sobre las anomalías, principalmente comparó las diferencias específicas entre las dos imágenes originales mencionadas anteriormente. Aquí scriptCode
se muestran ambos valores MD5 son diferentes, es decir, la descripción en sí scriptCode
(correspondiente al script de entrada de bloqueo) es inconsistente.
El punto básico encontró dónde está el problema, dados algunos de los cambios recientes, presumiblemente entryMethodParams
, y txContext
algunos de los parámetros de configuración pueden ser ineficaces. Así recalculado y actualizado preimage
, txContext.hex
, txContext.opReturn
los otros parámetros, depuración finalmente consiguieron los resultados correctos.
checkSig excepción
Existe una especie de error común que es checkSig
anormal, a menudo debido a problemas provocados por la firma. A continuación, podemos modificar libremente senderSig
para simular el valor del parámetro de error de un problema de firma; después de reiniciar Debug, puede ver la siguiente información:
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...
La información de solicitud anterior cubre los principales puntos de control al resolver errores de firma, a saber:
1. Determine si la clave privada utilizada para generar la firma es correcta;
2. Confirme si la preimagen del tx a firmar (calculada automáticamente según txContext) es consistente con los parámetros entrantes.
Para comparar si dos preimágenes iguales, pueden usarse SigHashPreimage
en toJSON()
un método para ver sus detalles internos, para obtener resultados similares a los siguientes:
{
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'
}
El truco aquí es: inserte un fragmento de código donde se genera la preimagen del parámetro de entrada, compárelo con la salida de la preimagen en el indicador de excepción anterior y descubra las posibles diferencias entre los dos. Como se muestra en el siguiente código:
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())
Debo recordarles una vez más que la configuración de inicio txContext
afectará el campo bajo los preimage
cálculos de atributos , y así uno por uno para confirmar si la misma comparación cuando un problema lo requiera.