Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provider refactor #61

Closed
wants to merge 20 commits into from
Closed

Provider refactor #61

wants to merge 20 commits into from

Conversation

HenryNguyen5
Copy link
Contributor

@HenryNguyen5 HenryNguyen5 commented Apr 30, 2018

Description

Adds much stricter typing to provider methods on both JSON RPC responses and requests

  • Uses Opaque type aliases  microsoft/TypeScript#15807 (comment) to enforce that string types for responses and requests are properly verified. E.g there are specific opaque types for

    • DATA Enforce that a string is of DATA type and variable length

    • DATA_8B Enforce DATA type and is of 8 bytes

    • DATA_20B Enforce DATA type and is of 20 bytes

    • DATA_32B Enforce DATA type and is of 32 bytes

    • DATA_256B Enforce DATA type and is of 256 bytes

    • DATA_60B Enforce DATA type and is of 60 bytes

    • QUANTITY Enforce QUANTITY type and is variable length

    • See https://github.com/ethereum/wiki/wiki/JSON-RPC#hex-value-encoding for more details
      This forces the usage of typeguard functions for each of the above types, so that each guarding function takes an input of string and returns one of the opaque types above. The advantage of this is that when you see a type such as DATA_8B, you know that it has already passed the string constraints of DATA type and is 8 bytes in length.

  • Uses https://github.com/MyCryptoHQ/eth-rpc-types, which is modeled as closely as possible to the Ethereum JSON-RPC spec for each provider method.

    • This makes sure that each one of our methods accepts the right parameters according to spec
    • Also enforces that the incoming responses are verified against the spec to reject bad responses properly
  • Fixes the inheritance structure of the providers so that they inherit from abstract classes, avoiding the problem of typecasting methods to any or some classes not supporting as many methods as others

Opaque type usage example

// Our custom opaque type
// type DATA_8B = string & {_tag : "__DATA_8B__"}

function verifyData8B(rawData: string): rawData is DATA_8B {
  const PREFIX_LEN = 2;
  if (!rawData.startsWith('0x')) {
    throw Error('Ethereum DATA type must start with a hex prefix');
  }
  if (rawData.length !== PREFIX_LEN + 16) {
    // 0x is 2 chars, then the rest is 8 chars, 2 chars per byte
    throw Error('Ethereum DATA_8B type must be 8 bytes long');
  } else {
    return !!(rawData as DATA_8B);
  }
}

function data8bEnforced(data: DATA_8B): Buffer {
  return Buffer.from(data, 'hex');
}

function unenforcedData8b(data: string): Buffer {
  return Buffer.from(data, 'hex');
}

const unsanitizedRequestData1 = 'hello';

/**
 * Argument of type '"hello"' is not assignable to parameter of type 'DATA_8B'.
 * Type '"hello"' is not assignable to type '{ _tag: "__DATA__8_BYTES"; }'

 * This is the error we want, so that it's properly enforced data type
 */
data8bEnforced(unsanitizedRequestData1);

/**
 * Now it works!
 * But because of our typeguard function,
 * it'll throw before undefined behaviour happens
 * This is exactly what we want
 */
verifyData8B(unsanitizedRequestData1) &&
  data8bEnforced(unsanitizedRequestData1);

/**
 * Works! But not what we want
 * This will cause behaviour we will not expect
 */
unenforcedData8b(unsanitizedRequestData1);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant