npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pine-rpc

v0.3.0

Published

Pine Is Not an Emulator — a standalone Ethereum JSON-RPC node backed by a smoldot light client, for pallet-revive on Polkadot Asset Hub. Run it as a daemon and point ethers / hardhat / foundry / MetaMask at it.

Downloads

147

Readme

pine-rpc

Pine Is Not an Emulator — a standalone Ethereum JSON-RPC node backed by a smoldot light client, for pallet-revive on Polkadot Asset Hub.

Pine boots a verifying light client in-process and translates Ethereum JSON-RPC calls (eth_*) into Substrate runtime API calls (ReviveApi_*, chainHead_v1_*). Run it as a daemon and point ethers / hardhat / foundry / MetaMask at it — no full archive node and no trust in a centralized RPC proxy required.

dApp / ethers / hardhat / cast / MetaMask
        │  eth_* JSON-RPC  (HTTP + WebSocket)
        ▼
   pine-rpc  ──►  PineProvider (EIP-1193)  ──►  smoldot light client  ──►  P2P

Pine is a light client, not a full node. It verifies Merkle proofs fetched over P2P; it has no historical archive. That makes some methods session-scoped or latest-only. Read SPEC.md for the exact per-method support matrix and limits — it is the source of truth.


Install

npm install -g pine-rpc
# or run without installing:
npx pine-rpc --chain paseo-asset-hub

Requires Node.js ≥ 18. Or skip Node entirely and use Docker:

docker run -p 8545:8545 ghcr.io/baronvonbonbon/pine-rpc --chain polkadot-asset-hub

Run the node

# Paseo Asset Hub testnet on http://127.0.0.1:8545 (+ ws://127.0.0.1:8545)
pine

# Polkadot Asset Hub mainnet on a custom port
pine --chain polkadot-asset-hub --port 9944

# Expose on the LAN (no auth — only behind a trusted network)
pine --host 0.0.0.0

First sync takes ~10–60 s (WASM init + P2P peer discovery + first finalized block). When ready you'll see:

  HTTP  http://127.0.0.1:8545
  WS    ws://127.0.0.1:8545
ready — press Ctrl+C to stop

GET /health returns 200 {"status":"ok"} once the light client is following finalized blocks (503 while starting) — use it for Docker HEALTHCHECK, systemd readiness, or load-balancer probes.

Point any Ethereum tool at it:

cast block-number --rpc-url http://127.0.0.1:8545
import { JsonRpcProvider } from "ethers";
const provider = new JsonRpcProvider("http://127.0.0.1:8545");
console.log(await provider.getBlockNumber());

CLI options

| Flag | Default | Description | |------|---------|-------------| | -c, --chain <preset> | paseo-asset-hub | paseo-asset-hub, polkadot-asset-hub, kusama-asset-hub, westend-asset-hub, or custom | | -p, --port <n> | 8545 | Listen port (HTTP + WS share it) | | -H, --host <addr> | 127.0.0.1 | Bind address | | --relay-chainspec <f> | — | Relay chain spec: file path or https:// URL. Required for custom; with a preset it overrides the bundled spec | | --para-chainspec <f> | — | Parachain spec: file path or https:// URL. Required for custom; overrides presets | | --para-id <n> | 1000 | Parachain id | | --chain-id <n> | preset value | EVM chain id for eth_chainId/net_version. Required for custom (must equal the runtime's Revive::ChainId) | | --log-window <n> | 10000 | eth_getLogs rolling window, in blocks | | --max-blocks <n> | 1024 | Tracked finalized-block cache size | | --timeout <ms> | 30000 | Connection timeout | | --no-ws | — | Disable WebSocket (HTTP only) | | --no-cors | — | Disable permissive CORS headers |

Run pine --help for the full list.

Supported chains

| Preset | Chain ID | Network | |--------|----------|---------| | paseo-asset-hub | 420420417 | Paseo testnet Asset Hub | | polkadot-asset-hub | 420420416 | Polkadot mainnet Asset Hub | | kusama-asset-hub | 420420418 | Kusama Asset Hub | | westend-asset-hub | 420420419 | Westend testnet Asset Hub | | custom | user-specified | Requires --relay-chainspec + --para-chainspec + --chain-id |

Chainspec flags accept a local file path or an https:// URL, and also work with presets to override the bundled spec — handy when a testnet migrates before the packaged spec catches up:

# Any pallet-revive chain, straight from hosted specs
pine --chain custom \
  --relay-chainspec https://example.com/my-relay.json \
  --para-chainspec  https://example.com/my-parachain.json \
  --chain-id 420420999

# Preset with a replacement relay spec
pine --chain paseo-asset-hub --relay-chainspec ./paseo-new.smol.json

JSON-RPC support

Supported (HTTP + WS): eth_blockNumber, eth_chainId, net_version, eth_gasPrice, eth_getBalance, eth_getStorageAt, eth_getTransactionCount, eth_call, eth_estimateGas, eth_sendRawTransaction, eth_getBlockByNumber / ByHash, eth_getBlockTransactionCountByNumber / ByHash, eth_getLogs, eth_getTransactionByHash, eth_getTransactionReceipt, web3_clientVersion, plus node-level eth_accounts, eth_syncing, net_listening, net_peerCount, web3_sha3, rpc_modules. Batch requests and standard JSON-RPC error envelopes are supported; ethers.js v6 works over both HTTP and WS.

Key limits (full detail and root causes in SPEC.md):

  • Light-client scope: no historical state — calls and queries execute against the latest finalized block; blocks, logs, and receipts are tracked in bounded in-memory windows from the moment Pine connects.
  • eth_getCode usually returns an error, not bytecode — current light-client peers do not serve the ReviveApi_get_code call proof. The error is bounded and descriptive; contract calls via eth_call work fine.
  • Explicit-number block lookups can return null even inside the tracked window — prefer "latest"/"finalized".
  • eth_getStorageAt requires a full 32-byte slot (ethers pads automatically); eth_estimateGas returns 0x0 for a plain value transfer.
  • eth_getTransactionByHash / eth_getTransactionReceipt are session-scoped: they cover transactions submitted through this Pine instance.

WebSocket subscriptions

The WS endpoint exposes eth_subscribe / eth_unsubscribe for newHeads and logs (address + topic filters); newPendingTransactions / syncing are rejected as unsupported. newHeads notifications arrive on each finalized block.

const ws = new WebSocket("ws://127.0.0.1:8545");
ws.send(JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_subscribe", params: ["newHeads"] }));

Use as a library

Pine is also importable. Embed the provider directly, or wrap it in the server:

import { PineProvider, JsonRpcServer } from "pine-rpc";

const provider = new PineProvider({ chain: "paseo-asset-hub" });
// or any pallet-revive chain:
//   new PineProvider({ chain: "custom", relayChainSpec, parachainChainSpec, chainId: 420420999 })
await provider.connect();

// (a) use the EIP-1193 provider in-process
const bal = await provider.request({ method: "eth_getBalance", params: ["0x…", "latest"] });

// (b) or expose it as a network node
const server = new JsonRpcServer(provider, { port: 8545 });
await server.listen();

Deploy as a service

  • Docker: docker run -p 8545:8545 ghcr.io/baronvonbonbon/pine-rpc — the image ships a HEALTHCHECK against /health and binds 0.0.0.0 inside the container. Pass any CLI flags after the image name.

  • systemd: a hardened unit file is provided at deploy/pine-rpc.service:

    sudo npm install -g pine-rpc
    sudo cp deploy/pine-rpc.service /etc/systemd/system/
    sudo systemctl enable --now pine-rpc

Pine has no built-in auth or rate limiting. Keep it on 127.0.0.1 (the default) or a trusted network; put a reverse proxy in front for anything public.

Develop

npm install
npm run build      # tsc → dist/
npm test           # vitest (unit + integration)
npm start          # run the built CLI

Known Paseo quirks handled

  • Paseo relay migration (2026-07-02): the old relay was retired and @polkadot-api/known-chains still points at it (dead bootnodes → smoldot stalls in peer discovery forever). Pine bundles the official replacement specs from paseo-network/paseo-chain-specs for the paseo-asset-hub preset.

  • eth_getTransactionReceipt returns null on the centralized Paseo eth-rpc proxy for confirmed txs — Pine rebuilds receipts from System.Events.

  • ReviveApi_balance returns EVM-scaled wei (not planck) — passed through directly.

  • chainHead_v1_follow may stall — the chain manager re-follows with backoff.

Full detail, including fundamental light-client limits, is in SPEC.md.

License

GPL-3.0-or-later. See LICENSE.