This guide gives an overview on common practices and technical standards shared within the EthereumJS
ecosystem.
Runtime environment for development is node.js.
Development should always be possible running latest LTS
Node.js version, see Node.js release schedule table.
Node Version | Status | Latest Status Change |
---|---|---|
Node.js 12 |
|
|
The usage of package-lock files has been discussed extensively within the EthereumJS community and team, see e.g. this thread for some background on discussions which took place.
Latest policy agreement here is that package-locks are not regarded as strictly necessary for the libraries but are recently under reconsideration due to other benefits (speed, caching, reliability, reproducibility, etc.) and using a lockfile is taken on a case-by-case basis.
All libraries are transpiled to a lower common denominator JavaScript version (see section below), this section describes what language features are agreed upon to be used in the non-transpiled source code of the libraries.
Features from the following JavaScript
version standards are safe to be used:
Be careful when using language features from the following JavaScript
standards:
- ES2016 (ES7)
- ES2017 (ES8)
- Beyond
BigInt
BigInt
support is an often requested feature within the EthereumJS
ecosystem and we are constantly re-evaluating usage. Current discussion state is that we are not quite there on the browser/runtime support side yet to integrate in the libraries, see e.g. Can I use bigint? page for context.
We are getting close though, so if you feel a pressing need here it might be worth to re-trigger the discussion.
All the major EthereumJS libraries use TypeScript,
TypeScript
version and configuration is centrally managed in the ethereumjs-config
typescript package.
Linting and formatting of package source code can be triggered on the different libraries with an npm run lint
respectively a npm run lint:fix
command from package.json
.
Tool usage and configuration is centrally managed in the ethereumjs-config
lint package.
For TypeScript
libraries, transpilation is done through the TypeScript
compiler tsc
command line tool.
See the ethereumjs-config
typescript tsconfig.*.json
files for an overview on transpilation targets.
The following table gives an overview on the targeted Node.js version support:
Node Version | Status | Latest Status Change |
---|---|---|
Node.js 4 | Dropped | 2018-10-01 |
Node.js 6 | Dropped | 2019-02-19 |
Node.js 8 | Dropped | 2020-01-29 |
Node.js 10 | Supported | 2020-03-01 |
Node.js 12 | Supported | 2019-06-01 |
Node.js 13 | Partly Supported | 2020-10-19 |
Node.js 14 | Mostly Untested | 2020-10-19 |
For a concrete overview on supported Node.js versions have a look at the GitHub Actions
CI setup within the .github
folder of a repository, see build.yml as an example from the merkle-patricia-tree
library.
Most libraries are tested with Karma for browser compatibility, see karma.conf.js from the merkle-patricia-tree
library for an example setup.
Releases on libraries follow Semantic Versioning, normally releases are published on npm and as a tagged release on GitHub in the Releases
section.
Every library contains a CHANGELOG.md
file in the root directory, listing the changes on the respective release versions (see e.g. CHANGELOG.md of the ethereumjs-util
library), the changelog entry is copied to the GitHub release section on publication of a new release.
Releases go through a PR (see example PR <https://github.com/ethereumjs/ethereumjs-util/pull/155/files> on ethereumjs-util
v6.0.0
release), containing the package.json
version number update, a new CHANGELOG entry and eventually some update on the docs.
We are using a feature-centric branching model, the GitHub flow model is coming very much close.
Development of new features is taking place on a dedicated branch and should have some descriptive name for the work done (e.g. api-doc-fixes
, remove-vm-accesses-to-statemanager-trie-cache
, new-bloom-filter-tests
).
Once work on the feature branch is completed and all tests and checks from CI (see continuous_integration
) pass it goes through a review and eventually discussion process and is afterwards merged into a protected master
branch. The master
branch should always be stable and theoretically ready for deployment.
Some guidelines for the EthereumJS
libraries when working with Git
version control:
Always do your work on a separate feature branch (see branching_model
), this also applies when doing work from an own fork of a library.
This makes it easier for reviewers and others interested to test your code locally by fetching your code changes from your remote feature branch.
If you have separate things you want to change on a library, do separate PRs for this. So if you e.g. have some ideas for how to improve the build process and want to fix some bug from an issue, these are two separate PRs.
This is a precondition for a successful review of a PR, since a reviewer has a smaller subset of changes and can connect changes definitively to a certain feature. It also avoids the situation where unexpected discussions and disagreements on a certain subfeature set blocks the whole PR with all other changes.
Make sure that you end up with a meaningful commit history on your work:
- Choose self-descriptive commit messages
- Avoid inconsistent state between commits
- If you do changes correcting your prior committed work, rebase and squash commits afterwards
Note
Rebasing can be a hairy process, if you do for the first time it is highly recommended to do a local backup of your repository.
Note
Rebase work like the above can normally be done with git rebase -i master
from the feature branch with an up-to-date master
branch.
PRs are only reviewed if the branch is up-to-date on the latest master
changes. Rebase your branch often (with git rebase master
) and force-push the changes, to make sure that your changes work well on top of the latest commits and tests keep passing.
Some best practices which turned out to be practical over time and should be followed when working on a new feature:
If you are planning on introducing major feature changes on a library file an issue and describe what you are up to before directly work on a PR. This gives others the chance to discuss around your intended changes and avoids potential further conflicts along the road.
This especially applies for stuff like:
- Introducing new language features (
Promises
,...) - Changing the API of a library
- Planning security-sensitive changes
- Switch or introduce new tooling
Take some time to make both the scope of your work and your work process transparent for others. This will ease both discussions and the review process around the work being done.
In particular:
- Do a proper and complete task description on your issue or PR
- Give some regular updates on the current status of your work
- Especially: drop a note once you are ready
All PRs making changes to the production code base are going through a review process. This will normally take some time and will come along with some back-and-forth between contributor and reviewer until everyone is happy.
Most EthereumJS
libraries use tape for running tests. Have a look at one of the libraries (e.g. merkle-patricia-tree) for reference.
For coverage runs nyc is used. Results are passed on to the coveralls.io service for coverage reports on CI runs.
Tool usage and configuration is centrally managed in the ethereumjs-config
coverage package.
Libraries come with an API documentation generated automatically from comments in the code.
To generate API documentation for a TypeScript project, TypeDoc is employed. By default, TypeDoc generates HTML documentation. In order to generate Markdown suitable for GitHub, the typedoc-plugin-markdown can be used as a theme for TypeDoc.
Apart from that, the following documentation should be kept up-to-date:
README
with setup and installation instructions- Usage instructions, up-to-date code examples
All EthereumJS
libraries use GitHub Actions <https://github.com/features/actions> for CI runs on every PR submitted. Have a look at the files in the .github/workflows
folder from a repository to get an overview on what is run during the CI process.
Security aspects around the EthereumJS libraries should be taken seriously, since many of the libraries are used in production in security-sensitive environments.
Dependencies are a main source for also importing security vulnerabilities on a library, so the set of dependencies on the libraries should be actively managed and regularly reviewed.
Some guidelines:
Every introduction of a new dependency on a library should be carefully considered and there has to be solid argument why a new dependency is necessary. This primarily applies for production but also for development dependencies. Dependencies listed in package.json
should be reviewed on a regular basis if they are still necessary or could be removed.
Only (somewhat) established and actively maintained dependencies should be used on the libraries. Some indicators for a not-so-established dependency:
- Low number of
GitHub
stars or a similar metric - No commit activity for a longer period of time
- Low download rate on
npm
Dependency versions should be updated on a regular basis, this is also very welcome to be done as a first-time-contributor
PR. Don't underestimate this task though, since a dependency update almost always comes along with some necessary changes on a library. It is recommended to always only do one dependency at a time, since it becomes easier to attribute if things break at some point.
The following libraries set up some shared infrastructure for certain purposes.
The ethereumjs-testing library is a proxy library for the common Ethereum Tests consensus tests.
The common test library is integrated as a submodule and there are tagged releases (no publishing to npm
due to size constraints) which can be used for running the latest tests in JavaScript
libraries.
The ethereumjs-config library provides a set of unified configuration options (e.g. on the TypeScript
configuration or on the linting setup) for the various EthereumJS
libraries.