Implementation
@override
Uint8List get hash {
// Remove OP_CODESEPERATOR from the script code
final correctedScriptSig = Script(
scriptCode.ops.where((op) => !op.match(_codeseperator)),
).compiled;
// If there is no matching output for SIGHASH_SINGLE, then return all null
// bytes apart from the last byte that should be 1
if (hashType.single && inputN >= tx.outputs.length) return _hashOne;
// Create modified transaction for obtaining a signature hash
final modifiedInputs = (
hashType.anyOneCanPay ? [tx.inputs[inputN]] : tx.inputs
).asMap().map(
(index, input) {
final isThisInput = hashType.anyOneCanPay || index == inputN;
return MapEntry(
index,
RawInput(
prevOut: input.prevOut,
// Use the corrected previous output script for the input being signed
// and blank scripts for all the others
scriptSig: isThisInput ? correctedScriptSig : Uint8List(0),
// Make sequence 0 for other inputs unless using SIGHASH_ALL
sequence: isThisInput || hashType.all ? input.sequence : 0,
),
);
}
).values;
final modifiedOutputs = hashType.all ? tx.outputs : (
hashType.none ? <Output>[] : [
// Single output
// Include blank outputs upto output index
...Iterable.generate(inputN, (i) => Output.blank()),
tx.outputs[inputN],
]
);
final modifiedTx = Transaction(
version: tx.version,
inputs: modifiedInputs,
outputs: modifiedOutputs,
locktime: tx.locktime,
);
// Add sighash type onto the end
final bytes = Uint8List(modifiedTx.size + 4);
final writer = BytesWriter(bytes);
modifiedTx.write(writer);
writer.writeUInt32(hashType.value);
// Use sha256d for signature hash
return sha256DoubleHash(bytes);
}