UNPKG

@ckb-lumos/toolkit

Version:

JavaScript toolkits used to build dapps for Nervos CKB

256 lines (254 loc) 10.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ValidateBlock = ValidateBlock; exports.ValidateCellDep = ValidateCellDep; exports.ValidateCellInput = ValidateCellInput; exports.ValidateCellOutput = ValidateCellOutput; exports.ValidateCellbaseWitness = ValidateCellbaseWitness; exports.ValidateHeader = ValidateHeader; exports.ValidateOutPoint = ValidateOutPoint; exports.ValidateRawHeader = ValidateRawHeader; exports.ValidateRawTransaction = ValidateRawTransaction; exports.ValidateScript = ValidateScript; exports.ValidateTransaction = ValidateTransaction; exports.ValidateUncleBlock = ValidateUncleBlock; exports.ValidateWitnessArgs = ValidateWitnessArgs; /* eslint-disable @typescript-eslint/no-unused-vars */ // This package provides validator functions that check JSON objects are // following the correct format, so we can submit them to CKB via RPC // directly function assertObject(debugPath, object) { if (!(object instanceof Object)) { throw new Error(`${debugPath} is not an object!`); } } function assertObjectWithKeys(debugPath, object, expectedKeys, optionalKeys = []) { assertObject(debugPath, object); const providedKeys = Object.keys(object).sort(); const requiredLength = expectedKeys.length; const maximalLength = expectedKeys.length + optionalKeys.length; const errorMessage = `${debugPath} does not have correct keys! Required keys: [${expectedKeys.sort().join(", ")}], optional keys: [${optionalKeys.sort().join(", ")}], actual keys: [${providedKeys.join(", ")}]`; if (providedKeys.length < requiredLength || providedKeys.length > maximalLength) { throw new Error(errorMessage); } let optionalProvidedKeys = providedKeys.filter(key => !expectedKeys.includes(key)); if (providedKeys.length - optionalProvidedKeys.length !== requiredLength) { throw new Error(errorMessage); } if (optionalProvidedKeys.find(key => !optionalKeys.includes(key))) { throw new Error(errorMessage); } } function assertHexString(debugPath, string) { if (!/^0x([0-9a-fA-F][0-9a-fA-F])*$/.test(string)) { throw new Error(`${debugPath} must be a hex string!`); } } function assertHash(debugPath, hash) { assertHexString(debugPath, hash); if (hash.length !== 66) { throw new Error(`${debugPath} must be a hex string of 66 bytes long!`); } } function assertInteger(debugPath, i) { if (i === "0x0") { return; } if (!/^0x[1-9a-fA-F][0-9a-fA-F]*$/.test(i)) { throw new Error(`${debugPath} must be a hex integer!`); } } function ValidateScript(script, { nestedValidation = true, debugPath = "script" } = {}) { assertObjectWithKeys(debugPath, script, ["codeHash", "hashType", "args"], []); assertHash(`${debugPath}.codeHash`, script.codeHash); assertHexString(`${debugPath}.args`, script.args); if (script.hashType !== "data" && script.hashType !== "type" && script.hashType !== "data1" && script.hashType !== "data2") { throw new Error(`${debugPath}.hashType must be either data or type!`); } } function ValidateOutPoint(outPoint, { nestedValidation = true, debugPath = "outPoint" } = {}) { assertObjectWithKeys(debugPath, outPoint, ["txHash", "index"], []); assertHash(`${debugPath}.txHash`, outPoint.txHash); assertInteger(`${debugPath}.index`, outPoint.index); } function ValidateCellInput(cellInput, { nestedValidation = true, debugPath = "cellInput" } = {}) { assertObjectWithKeys(debugPath, cellInput, ["since", "previousOutput"], []); assertInteger(`${debugPath}.since`, cellInput.since); if (nestedValidation) { ValidateOutPoint(cellInput.previousOutput, { debugPath: `${debugPath}.previousOutput` }); } } function ValidateCellOutput(cellOutput, { nestedValidation = true, debugPath = "cellOutput" } = {}) { assertObjectWithKeys(debugPath, cellOutput, ["capacity", "lock"], ["type"]); assertInteger(`${debugPath}.capacity`, cellOutput.capacity); if (nestedValidation) { ValidateScript(cellOutput.lock, { debugPath: `${debugPath}.lock` }); if (cellOutput.type) { ValidateScript(cellOutput.type, { debugPath: `${debugPath}.type` }); } } } function ValidateCellDep(cellDep, { nestedValidation = true, debugPath = "cellDep" } = {}) { assertObjectWithKeys(debugPath, cellDep, ["outPoint", "depType"], []); if (cellDep.depType !== "code" && cellDep.depType !== "depGroup") { throw new Error(`${debugPath}.depType must be either code or depGroup!`); } if (nestedValidation) { ValidateOutPoint(cellDep.outPoint, { debugPath: `${debugPath}.outPoint` }); } } function assertArray(debugPath, array, validateFunction, nestedValidation) { if (!Array.isArray(array)) { throw new Error(`${debugPath} is not an array!`); } if (nestedValidation) { for (let i = 0; i < array.length; i++) { validateFunction(`${debugPath}[${i}]`, array[i]); } } } function toAssert(validateFunction, nestedValidation) { return function (debugPath, value) { validateFunction(value, { nestedValidation: nestedValidation, debugPath: debugPath }); }; } function assertCommonTransaction(debugPath, rawTransaction, nestedValidation) { assertInteger(`${debugPath}.version`, rawTransaction.version); assertArray(`${debugPath}.cellDeps`, rawTransaction.cellDeps, toAssert(ValidateCellDep, nestedValidation), nestedValidation); assertArray(`${debugPath}.headerDeps`, rawTransaction.headerDeps, assertHash, nestedValidation); assertArray(`${debugPath}.inputs`, rawTransaction.inputs, toAssert(ValidateCellInput, nestedValidation), nestedValidation); assertArray(`${debugPath}.outputs`, rawTransaction.outputs, toAssert(ValidateCellOutput, nestedValidation), nestedValidation); assertArray(`${debugPath}.outputsData`, rawTransaction.outputsData, assertHexString, nestedValidation); } function ValidateRawTransaction(rawTransaction, { nestedValidation = true, debugPath = "rawTransaction" } = {}) { assertObjectWithKeys(debugPath, rawTransaction, ["version", "cellDeps", "headerDeps", "inputs", "outputs", "outputsData"], []); assertCommonTransaction(debugPath, rawTransaction, nestedValidation); } function ValidateTransaction(transaction, { nestedValidation = true, debugPath = "transaction" } = {}) { assertObjectWithKeys(debugPath, transaction, ["version", "cellDeps", "headerDeps", "inputs", "outputs", "outputsData", "witnesses"], []); assertCommonTransaction(debugPath, transaction, nestedValidation); assertArray(`${debugPath}.witnesses`, transaction.witnesses, assertHexString, nestedValidation); } function assertCommonHeader(debugPath, rawHeader) { assertInteger(`${debugPath}.version`, rawHeader.version); assertInteger(`${debugPath}.compactTarget`, rawHeader.compactTarget); assertInteger(`${debugPath}.timestamp`, rawHeader.timestamp); assertInteger(`${debugPath}.number`, rawHeader.number); assertInteger(`${debugPath}.epoch`, rawHeader.epoch); assertHash(`${debugPath}.parentHash`, rawHeader.parentHash); assertHash(`${debugPath}.transactionsRoot`, rawHeader.transactionsRoot); assertHash(`${debugPath}.proposalsHash`, rawHeader.proposalsHash); assertHash(`${debugPath}.extraHash`, rawHeader.extraHash); assertHash(`${debugPath}.dao`, rawHeader.dao); } function ValidateRawHeader(rawHeader, { nestedValidation = true, debugPath = "rawHeader" } = {}) { assertObjectWithKeys(debugPath, rawHeader, ["version", "compactTarget", "timestamp", "number", "epoch", "parentHash", "transactionsRoot", "proposalsHash", "extraHash", "dao"], []); assertCommonHeader(debugPath, rawHeader); } function ValidateHeader(header, { nestedValidation = true, debugPath = "header" } = {}) { assertObjectWithKeys(debugPath, header, ["version", "compactTarget", "timestamp", "number", "epoch", "parentHash", "transactionsRoot", "proposalsHash", "extraHash", "dao", "nonce"], []); assertHexString(`${debugPath}.nonce`, header.nonce); if (header.nonce.length !== 34) { throw new Error(`${debugPath}.nonce must be a hex string of 34 bytes long!`); } } function assertProposalShortId(debugPath, shortId) { assertHexString(debugPath, shortId); if (shortId.length !== 22) { throw new Error(`${debugPath} must be a hex string of 22 bytes long!`); } } function ValidateUncleBlock(uncleBlock, { nestedValidation = true, debugPath = "uncleBlock" } = {}) { assertObjectWithKeys(debugPath, uncleBlock, ["header", "proposals"], []); if (nestedValidation) { ValidateHeader(uncleBlock.header, { debugPath: `${debugPath}.header` }); } assertArray(`${debugPath}.proposals`, uncleBlock.proposals, assertProposalShortId, nestedValidation); } function ValidateBlock(block, { nestedValidation = true, debugPath = "block" } = {}) { assertObjectWithKeys(debugPath, block, ["header", "uncles", "transactions", "proposals"], []); if (nestedValidation) { ValidateHeader(block.header, { debugPath: `${debugPath}.header` }); } assertArray(`${debugPath}.uncles`, block.uncles, toAssert(ValidateUncleBlock, nestedValidation), nestedValidation); assertArray(`${debugPath}.transactions`, block.transactions, toAssert(ValidateTransaction, nestedValidation), nestedValidation); assertArray(`${debugPath}.proposals`, block.proposals, assertProposalShortId, nestedValidation); } function ValidateCellbaseWitness(cellbaseWitness, { nestedValidation = true, debugPath = "cellbaseWitness" } = {}) { assertObjectWithKeys(debugPath, cellbaseWitness, ["lock", "message"], []); assertHexString(`${debugPath}.message`, cellbaseWitness.message); if (nestedValidation) { ValidateScript(cellbaseWitness.lock, { debugPath: `${debugPath}.lock` }); } } function ValidateWitnessArgs(witnessArgs, { nestedValidation = true, debugPath = "witnessArgs" } = {}) { assertObjectWithKeys(debugPath, witnessArgs, [], ["lock", "inputType", "outputType"]); if (witnessArgs.lock) { assertHexString(`${debugPath}.lock`, witnessArgs.lock); } if (witnessArgs.inputType) { assertHexString(`${debugPath}.inputType`, witnessArgs.inputType); } if (witnessArgs.outputType) { assertHexString(`${debugPath}.outputType`, witnessArgs.outputType); } } //# sourceMappingURL=validators.js.map