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

Enable TypeScript/JavaScript implementation to be used in a browser #609

Open
bestbeforetoday opened this issue Jun 28, 2023 · 7 comments · May be fixed by #701
Open

Enable TypeScript/JavaScript implementation to be used in a browser #609

bestbeforetoday opened this issue Jun 28, 2023 · 7 comments · May be fixed by #701
Assignees
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@bestbeforetoday
Copy link
Member

bestbeforetoday commented Jun 28, 2023

As a front-end developer
I want to use the client API directly from the browser
So that a back-end Node.js server is not required as an intermediary

The key issues are the use of Node packages in the implementation, and some exposure of Node packages in the public API. This includes:

The core of the implementation either is or can be implemented without using any Node-specific packages. A workable approach seems to be to split this core capability out into a separate package, which can be depended on by the fabric-gateway package. The fabric-gateway package will then only contain Node-specific additions, such as the default signer, hash and checkpointer implementations. @noble/hashes should provide secure random and hash implementations required by the core package (for transactioncontext.ts) without any dependency on Node.js.

The alternatives available with the existing implementation are:

  1. Use a Node.js back-end server do interact with Fabric on behalf of the browser using the fabric-gateway API, and the off-line signing flow to enable the browser to handle signing using the signing credentials held there.
  2. Use the Gateway gRPC service directly using the @hyperledger/fabric-protos package.
@bestbeforetoday bestbeforetoday added the enhancement New feature or request label Jun 28, 2023
@bestbeforetoday
Copy link
Member Author

I created a prototype implementation by:

  1. Move all the Node client code that can be implemented without using Node standard packages into a node/src/core sub-directory. This required:
    1. Implement a simple alternative to a usage of util.inspect in transactionparser.ts.
    2. Use @noble/hashes/sha256 for SHA-256 hash in signingidentity.ts and transactioncontext.ts.
    3. Use @noble/hashes/utils for randomBytes in transactioncontext.ts.
    4. The few files and index.ts remaining in the top-level node/src import (and export) node/src/core as required.
  2. Add an node/src/core/index.ts file to act as a single entry point to all the pure JavaScript code.
  3. Use esbuild to generate a single bundle.js file from all the content in node/dist/core.

The restructuring of the code seems to be successful but the bundling process highlighted that @grpc/grpc-js itself relies on several built-in Node packages. These can be polyfilled but whether or not it will work with these polyfills is uncertain. A fully browser-compatible (no polyfill) implementation would probably need grpc-web to be used instead of @grpc/grpc-js. This appears at first look to be impractical since:

  1. grpc-web currently does not provide all the required gRPC capability. Bi-directional streaming (used for block eventing) is not supported.
  2. The fabric-gateway API accepts a grpc-js Client object as the gRPC connection to use.

@bestbeforetoday
Copy link
Member Author

bestbeforetoday commented Oct 6, 2023

My current thinking is that refactoring the current Node implementation so that it (or parts of it) can be run in a browser environment is impractical. It probably makes sense to make use of the WebCrypto (SubtleCrypto) API, and the digest() function it provides is asynchronous. This would cause a breaking change to the synchronous getDigest() and (to a lesser extent) Hash functions exposed by the Fabric Gateway client API.

Since the primary use case is to modify the off-line signing flow by both generating and signing request messages at the client to avoid the need for the server to generate messages and return them to the client for signing, a more practical approach might be to lift and refactor a subset of the existing code out into a separate browser package. This would include capability to:

  • Directly build cut-down variants of the Proposal, Transaction, Commit and ChaincodeEventsRequest objects.
  • The built objects would only provide capability to:
    • Serialize themselves - equivalent of getBytes().
    • Return the full message content to be signed - equivalent of getDigest() when the none hash is used to pass back the message unaltered.

An optional addition would be to directly build similar, cut-down variants of the block event request objects: FilteredBlockEventsRequest, BlockEventsRequest and BlockAndPrivateDataEventsRequest.

The fabric-protos package also has a dependency on @grpc/grpc-js since it includes gRPC service stubs. As described in previous comments, @grpc/grpc-js has dependencies on many standard Node packages. It might be necessary to build and package within this browser package a subset of the fabric-protos, including only the ones needed to build the objects described above, and excluding gRPC services. Since the browser environment would only interact with the Fabric Gateway client API indirectly by passing serialised protocol buffer messages, this should not present a compatibility problem, since wire-level interoperability of serialized protocol buffer messages is robust.

@bestbeforetoday bestbeforetoday added the help wanted Extra attention is needed label Jan 13, 2024
@bestbeforetoday bestbeforetoday self-assigned this Apr 4, 2024
@bestbeforetoday bestbeforetoday linked a pull request Apr 4, 2024 that will close this issue
@seina-webisoft
Copy link

Hi! Do you have a status update on this issue? I see your PR has been in draft since April, and I'd love for this feature to be merged

@bestbeforetoday
Copy link
Member Author

My progress on this stalled, partly due to time commitments and largely due to my lack of experience in developing, packaging and testing bundles for the browser. The people who were interested in this capability also went quiet. With nobody actively looking to make use of it, development took a back seat to other things.

If you (or anyone else) can provide some guidance (or help) on some of the areas I am lacking experience, I would really like to get this done.

I have rebased my working branch on the latest main branch content, and you can find it here. The actual implementation is pretty well complete. If you want to pull down that branch and build the Web bundle with make build-web, you should get web/fabric-gateway-web.js as output. I would be really interested to see if it is usable for you.

You can generate API documentation with make generate-docs-web. You should find content with example code at web/apidocs/index.html.

@seina-webisoft
Copy link

Sounds good! I've dabbled in module development, and I'd be happy to take a look and help out where I can.

I'll try pulling your changes and testing them out. In the meantime, could you let me know what areas specifically I can offer help?

Thanks for supporting this issue, I really appreciate it!

@bestbeforetoday
Copy link
Member Author

The main thing is whether the code (currently output to web/fabric-gateway-web.js) is packaged in a way that is usable and works in a browser. I don't know:

  1. If optimal TypeScript compiler options are used.
  2. If bundling the code in a single .js file is ideal.
  3. If the public API is exported from the bundle in the best way for browser consumption.
  4. The best way to publish the finished output — just attached to a GitHub release as a release artefact, or something else?

The unit test coverage is pretty comprehensive so it should work OK. I would feel more comfortable with some scenario tests that drive a transaction end-to-end into a running Fabric, which I have not yet done. If I can get good answers to the questions above, implement any changes necessary based on that, and the code works with some hands-on testing, perhaps it could be released sooner and I can work on scenario testing later.

@seina-webisoft
Copy link

seina-webisoft commented Dec 12, 2024

Ok great, so at first glance here's what I would propose:

  1. The tsconfig.json setup seems pretty standard. Since you're transpiling with ESBuild, some settings (like "declaration": true, for example), won't affect the bundled code. TypeScript is being used more like a linter/typechecker in this case, which is perfectly fine, I would probably even keep these settings in case a different bundler is used in the future. You can see the tsconfig attributes ESBuild inspects here.
    In addition to the current setup, I would also suggest enabling noUncheckedIndexedAccess, as well as noImplicitOverride, especially because we're dealing with classes (though I don't see any inheritance being used so it won't really affect the existing code).
  2. How you bundle the code is up to you. I think a single minified file with dependencies included works in a vanilla browser context where we're loading the js in a script tag. I would also suggest bundling for modules (ESM and CJS) for maximum compatibility. In this case, we can omit external dependencies from the final bundle. This will significantly reduce the bundle size and help avoid code redundancy if, say, a dependency is already installed within the project.
  3. The API seems fine from what I could tell. I would have to play around with it to be 100% certain.
  4. This depends on the bundle. For the browser, you would normally serve the minified js file via a CDN of some sort. It looks like this can be done with GitHub Pages, but this seems more like a workaround than an actual solution (but whatever works, right?). The modules can be deployed to the public npm registry, in the same way the node package is being deployed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants