=nil; is a sharded blockchain whose global state is split between several execution shards. Execution shards are managed by a single main shard that references the latest blocks across all execution shards. Each new block produced in an execution shard must also reference the latest block in the main shard.
This project is an implementation of =nil; in Go.
Documentation · Block explorer · Playground
- Building and using the project
- Unique features
- Repository structure
- The RPC
- Open RPC spec generator
- Linting
- Packaging
- Debugging
Install Nix:
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- installEnter the Nix development environment:
cd nil
nix developBuild the project and binaries with:
makeTo run the cluster:
./build/bin/nild run --http-port 8529To run the faucet service:
./build/bin/faucet runTo run the Cometa service:
./build/bin/cometa runTo run the load generator:
./build/bin/nil_load_generatorTo access the =nil; CLI:
./build/bin/nilThe repository uses Nix for dependency and project management.
To enter the Nix development environment:
nix develop .#DERIVATION_NAMETo build a project according to its derivation:
nix build .#DERIVATION_NAMEThe repository uses NPM Workspaces to manage collective dependencies across the JS/TS projects it is hosting.
There can only be one top-level package-lock.json file that can be regenerated as follows:
npm run install:cleanIndividual projects should not have separate package-lock.json files. If such files exist, it may lead to unintended behaviors.
In addition, Nix validates the hashum of the package-lock.json file when building the project. Perform the following actions after running the install:clean script:
- Open the
./nix/npmdeps.nixfile - Remove the current hashsum (located under the list of all
package.jsonfiles) - Attempt to enter the Nix environment by running
nix develop .#DERIVATION_NAME - Wait for Nix to provide the correct hash
- Place the correct hash inside the
./nix/npmdeps.nixfile
Run tests with:
make testRun the below command to generate the SSZ serialization code:
make sszmake compile-contracts=nil; boasts several unique features making it distinct from Ethereum and other L2s.
- Structurally distinct external and internal transactions
- Async execution
- Cross-shard communications without fragmentation
The cluster source code is available at ./nil.
To interact with the cluster, =nil; supplies several developer tools.
- The =nil; CLI (
./nil/cmd/nil) - The
Nil.jsclient library (./niljs) - A generator for pre-configured Hardhat projects (
./create-nil-hardhat-project) - The block explorer and the Playground (
./explorer_backendand./explorer_frontend) - The
smart-contractsNPM package containing Solidity libraries for interacting with =nil;
The repository also houses the following projects:
./clijs, a re-write of the =nil; CLI using JS/TS./docs, the =nil; documentation available at https://docs.nil.foundation./docs_ai_backend, a Next.js app handling the RAG chatbot available inside the =nil; documentation./explorer_frontendand./explorer_backend, the two core components of the =nil; block explorer and Playground./l1-contracts, the =nil; contracts to be deployed on Ethereum./uniswap, an implementation of the Uniswap V2 protocol on =nil;
The ./nix folder houses Nix derivations.
The current RPC is loosely modeled after the Ethereum RPC. The RPC exposes the following methods.
GetBlockByNumber()GetBlockByHash()GetBlockTransactionCountByNumber()GetBlockTransactionCountByHash()
GetInTransactionByHash()GetInTransactionByBlockHashAndIndex()GetInTransactionByBlockNumberAndIndex()GetRawInTransactionByBlockNumberAndIndex()GetRawInTransactionByBlockHashAndIndex()GetRawInTransactionByHash()
GetInTransactionReceipt()
GetBalance()GetCode()GetTransactionCount()GetTokens()
SendRawTransaction()
NewFilter()NewPendingTransactionFilter()NewBlockFilter()UninstallFilter()GetFilterChanges()GetFilterLogs()GetShardIdList()
GetShardIdList()GetNumShards()
Call()
ChainId()
The project also includes a generator of an OpenRPC spec file from the type definitions of the RPC API interface.
The primary benefit of this is allowing for automatic RPC API documentation generation on the side of the documentation portal.
Another benefit is greater coupling of docs and code. Do not hesitate to adjust the doc strings (be mindful to follow the doc string spec) in rpc/jsonrpc/eth_api.go, rpc/jsonrpc/types.go and rpc/jsonrpc/doc.go to account for latest changes in the RPC API. All changes will make their way to the documentation portal without any overhead.
To run the spec generator:
cp nil/cmd/spec_generator/spec_generator.go .
go run spec_generator.
rm spec_generator.goThis will produce the openrpc.json file in the root directory.
The project uses golangci-lint, a linter runner for Go.
All linters are downloaded and built as part of the nix develop command. Run linters with:
make lint.golangci.yml contains the configuration for golangci-lint, including the
full list of all linters used in the project.
Create a platform-agnostic deb package:
nix bundle --bundler . .#nil
=nil; allows for reproducing execution of a particular block. To do so, run the cluster in the block-replay mode:
nild --db-path ./database replay-block --first-block STARTING_BLOCK --last-block FINAL_BLOCK --shard-id SHARD_ID --log-level traceNB: by default, the replay mode fully copies the existing production DB. It is possible to avoid this by only fetching the required records. Use the read-through mode to do so:
nild --read-through-db-addr $RPC_ENDPOINT --read-through-fork-main-at-block FORK_NUM replay-block --first-block STARTING_BLOCK --last-block FINAL_BLOCK --shard-id SHARD_ID --log-level traceThe FORK_NUM placeholder represents the number of blocks beyond which records will not be retrieved from the production DB.