Durante o desenvolvimento e depuração do contrato sCrypt, os dois problemas mais comuns e mais problemáticos são as exceções checkSig e checkPreimage. Embora possamos localizar o local específico do erro no código-fonte durante a depuração, sempre nos sentimos confusos sobre o motivo da falha e como corrigi-lo. Hoje vamos falar sobre algumas dicas de como localizar e reparar rapidamente esses dois tipos de problemas, na esperança de ser útil a todos.
O projeto padrão sCrypt contém alguns códigos de amostra específicos do contrato sCrypt e está em constante atualização, portanto, às vezes você pode encontrar uma situação em que a configuração falha e a depuração não pode ser concluída normalmente. Vamos tomar o contrato tokenUtxo neste projeto como um exemplo para ver como localizar e resolver esses dois tipos de problemas.
Observação: a versão do plug-in sCrypt usado neste artigo é 0.4.3 .
exceção checkPreimage
Primeiro, observe tokenUtxo.scrypt
a configuração de inicialização de depuração (localizada .vscode / launch.json para conveniência, visualize os 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
}
}
A configuração de depuração acima especifica a função inicial split
e entryMethodParams
os parâmetros especificam o número inicial; o mesmo txContext
parâmetro de contexto especificado de tempo relacionado a tx. Quando iniciamos essa configuração em vscode para nos prepararmos para a depuração, descobrimos que a seguinte exceção foi gerada no Console de depuração:
Execution failed with error SCRIPT_ERR_NULLFAIL.
Stacktrace:
/Users/hero/work/boilerplate/contracts/tokenUtxo.scrypt:14:in 'Token.split'
A localização anormal mostrada aqui está na linha 14, e o código é require(Tx.checkPreimage(txPreimage));
. A partir disso, pode-se inferir que há um problema com txPreimage, mas qual é o motivo específico?
No artigo anterior , apresentamos Sighash Preiamge, que é chamado de pré-imagem da transação e pode ser calculado pela transação tx. Aqui Tx.checkPreimage
falha, os parâmetros de configuração de inicialização entryMethodParams
passados no valor e usam txContext
os parâmetros calculados do resultado são inconsistentes.
Conforme mostrado na figura acima, a pré-imagem de Sighash é composta de várias partes. Se as duas pré-imagens forem inconsistentes, alguns dos campos devem ser diferentes. Qual campo é o problema? Vejamos o seguinte log novamente:
----- 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 -----
Este diário nos fornece checkPreimage
mais detalhes sobre anormalidades, principalmente comparando as diferenças específicas entre as duas imagens originais mencionadas anteriormente. Aqui, ambos os scriptCode
valores MD5 são diferentes, ou seja, a descrição em si scriptCode
(correspondente ao script de entrada de bloqueio) é inconsistente.
O ponto básico encontrado onde está o problema, dadas algumas das mudanças recentes, presumivelmente entryMethodParams
, e txContext
alguns dos parâmetros de configuração podem ser ineficazes. Então recalculados e atualizados preimage
, txContext.hex
, txContext.opReturn
os outros parâmetros, Debug finalmente os resultados corretos.
exceção checkSig
Existe um tipo de erro comum é checkSig
anormal, muitas vezes devido a problemas de assinatura causados. Aqui, podemos ser modificados livremente senderSig
para simular o valor do parâmetro de erro de um problema de assinatura. Depois de reiniciar o Debug, você pode ver as seguintes informações:
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...
As informações de prompt acima abrangem os principais pontos de verificação ao resolver erros de assinatura, a saber:
1. Determine se a chave privada usada para gerar a assinatura está correta;
2. Confirme se a pré-imagem do tx a ser assinado (calculado automaticamente de acordo com txContext) é consistente com os parâmetros de entrada.
Para comparar se duas pré-imagem são iguais, pode ser usado SigHashPreimage
em toJSON()
um método para visualizar seus detalhes internos, para obter resultados semelhantes aos seguintes:
{
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'
}
O truque aqui é: insira um pedaço de código onde o parâmetro de entrada preimage é gerado, compare-o com a saída de preimage no prompt de exceção acima e descubra as possíveis diferenças entre os dois. Conforme mostrado no seguinte 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())
Devo lembrar mais uma vez que a configuração de inicialização txContext
afetará o campo sob os preimage
cálculos dos atributos , e assim um a um para confirmar se a mesma comparação quando um problema exige.