Skip to content
This repository has been archived by the owner on Jun 20, 2024. It is now read-only.

Error messaging for ValidateSPV.js #77

Open
barbaraliau opened this issue Oct 28, 2019 · 1 comment
Open

Error messaging for ValidateSPV.js #77

barbaraliau opened this issue Oct 28, 2019 · 1 comment
Assignees
Labels
enhancement New feature or request javascript Needs work in JS folder

Comments

@barbaraliau
Copy link
Member

ValidateSPV.validateHeaderChain() returns one of three different errors if it fails.

export function validateHeaderChain(headers) {
  // Check header chain length
  if (headers.length % 80 !== 0) {
    throw new TypeError('Header bytes not multiple of 80.');
  }

  let digest;
  let totalDifficulty = BigInt(0);

  for (let i = 0; i < headers.length / 80; i += 1) {
    // ith header start index and ith header
    const start = i * 80;
    const header = utils.safeSlice(headers, start, start + 80);

    // After the first header, check that headers are in a chain
    if (i !== 0) {
      if (!validateHeaderPrevHash(header, digest)) {
        throw new Error('Header bytes not a valid chain.');
      }
    }

    // ith header target
    const target = BTCUtils.extractTarget(header);

    // Require that the header has sufficient work
    digest = BTCUtils.hash256(header);
    if (!validateHeaderWork(digest, target)) {
      throw new Error('Header does not meet its own difficulty target.');
    }

    totalDifficulty += BTCUtils.calculateDifficulty(target);
  }
  return totalDifficulty;
}

When using this externally, this means having to do a switch/case to handle for each of the different errors messages. Comparing string error messages is prone to breakage if the message ever changes, and not optimal.

// Current implementation when using externally
    switch (e.message) {
      case 'Header bytes not multiple of 80.':
        return [false, errors.ERR_INVALID_CHAIN];
      case 'Header bytes not a valid chain.':
        return [false, errors.ERR_INVALID_PREV_BLOCK];
      case 'Header does not meet its own difficulty target.':
        return [false, errors.ERR_INVALID_PROOF_OF_WORK];
      default:
        return [false, errors.ERR_INVALID_CHAIN];
    }

Suggestions:

  1. Return error codes. This requires keeping a file of error codes. The advantage is the message can change but the code remains the same. Examples:
  • 1 is header length error
  • 2is invalid chain
  • 3 is doesn't meet difficulty target
    This option is a bit more time intensive to implement, and also requires the user to lookup the error codes to know what they mean.
// custom error code implementation
    switch (e.message) {
      case 1:
        return [false, errors.ERR_INVALID_CHAIN];
      case 2:
        return [false, errors.ERR_INVALID_PREV_BLOCK];
      case 3:
        return [false, errors.ERR_INVALID_PROOF_OF_WORK];
      default:
        return [false, errors.ERR_INVALID_CHAIN];
    }
  1. Throw a different type of error per error. This would be quickest to implement, and error messages can be bubbled up. Example:
  • throw new TypeError('Header bytes not multiple of 80.')
  • throw new Error('Header bytes not a valid chain.')
    -throw new RangeError('Header does not meet its own difficulty target.')

The user can compare types of errors and handle it appropriately.

// Error types implementation
    switch (e) {
      case instanceof TypeError:
        return [false, errors.ERR_INVALID_CHAIN];
      case instanceof RangeError:
        return [false, errors.ERR_INVALID_PROOF_OF_WORK];
      case instanceof Error:
        return [false, errors.ERR_INVALID_PREV_BLOCK];
      default:
        return [false, errors.ERR_INVALID_CHAIN];
    }

The obvious disadvantage to this is there is a limited amount of error types, and the default is never going to be reached since all error types are Errors. New error types can be constructed, which might be a nice combination of both of these suggestions.

  • PrevBlockError
  • PrevHashError
  • MerkleRootError

Maybe we can compile some sort of shared bitcoin/blockchain specific error codes that can be used across projects.

@barbaraliau barbaraliau added enhancement New feature or request javascript Needs work in JS folder labels Oct 28, 2019
@prestwich
Copy link
Member

prestwich commented Oct 28, 2019

@ErinHales check the solidity behavior. it has hard-coded error code integers that are set as constants.

Use Barbara's suggestion 1 to remove all throws from bitcoin-spv/js

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request javascript Needs work in JS folder
Projects
None yet
Development

No branches or pull requests

3 participants