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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@starton/evm-mock-server

v0.8.1

Published

Simulate an EVM server to replicate forks, delays, and other impactful blockchain events. Enhance the robustness of your web3 development with tools like viem, etherjs, web3js, or your own library through the power of comprehensive testing!

Downloads

20

Readme

Starton Banner

EvmMockServer

EvmMockServer is a tool designed to simulate real-world blockchain environments. It's currently a work in progress, crafted to replicate challenging scenarios such as high transaction traffic, slow node responses, and, most importantly, forks in the blockchain.

You can seamlessly integrate EvmMockServer with projects like etherjs, viem, or other libraries from different programming languages.

Requirements

You will need :

Installation

To install the project, first clone the repository and go inside project directory, then :

  • With NPM :
    $ npm install @starton/evm-mock-server

Usage

EvmMockServer is built to help you create simple blockchain scenarios, ensuring that the web3 systems you develop are stable and robust against errors that may occur in real-world situations.

To provide maximum flexibility, we've divided our mock system into two essential components:

1. Data Generator

Create simple blockchain scenarios that you can store in JSON format and modify independently. This allows you to generate pre-made fixtures for your tests, ensuring that you have fixed test data to validate every aspect of your application.

In this part we will see how to create two very basic scenario with a block that is valid, then a scenario where the block on the first read has an invalid receipt and get replaced by one with a valid receipt. The exemples are based on this structure

interface BlockGeneration {
  blockStartNumber: string; // The block number that will be converted to bigint and hexa later
  blockSeriesLength: number; // The number of blocks to generate
  blockInitParentHash?: string; // Initial parent hash for your first block
  block?: Record<string, BlockConfig>; // Specific configuration for each block, key is block number
}

interface FakeGeneration {
  initialSerie: BlockGeneration; // Generate a list of blocks based on configuration
  forkSerie?: BlockGeneration; // Generate blocks that will be swapped later as the main block

  forkType?: ReplaceType; // Option to determine how to base the swapped block when a fork occurs
  delayIndexMs?: number; // When calling the next block, allow the block index to change based on time
  increaseIndex?: number; // When calling the next block, set the next block number to be retrieved
  chainId?: number; // Specify a chainID otherwise will be 1
}

You will also have the option to create models to represent your block, transaction, receipt or log. This is useful to simulate errors that the server could send. You can use those function to create a new structure for example

import { evmMockServer, evmCreateOrUpdateModel, evmGetModel } from '@starton/evm-mock-server';
const block = evmGetModel('default:block');
console.log(block); // display the basic block structure with data inside. model based on plygon block
const newModel = '{ "number": "0x0000" }';
evmCreateOrUpdateModel("custom:test", newModel); // this will create a new model that you can use
// an exemple of already existing model used can be found in the second exemple below
  1. Exemple of a simple block with fixture file created
import { evmMockServer } from '@starton/evm-mock-server';
import { writeFile } from 'node:fs';
const rpcUrl = 'http://localhost:55001/unique';
const blockNumber = '43439028';
// no need to create a new data for this, we use basic model so all is known in advance
const response = await fetch(rpcUrl, {
  method: "PUT",
  body: JSON.stringify({
    initialSerie: {
        blockStartNumber: blockNumber,
        blockSeriesLength: 1
    }
  })
})
writeFile('./fixture-simple.json', JSON.stringify((await response.json()), null, 2), (error) => {
  if (error) {
    console.log('An error has occurred ', error);
    return;
  }
  console.log('Data written successfully to disk');
});
  1. Example with a fork occuring after the first block is called and read
import { evmMockServer, evmMockUtils } from '@starton/evm-mock-server';
const rpcUrl = 'http://localhost:55001/unique';
const blockNumber = '43439028';
// this generate hash with default length found in blocks and transactions
const forkedHash = evmMockUtils.randomHash();
const validHash = evmMockUtils.randomHash();
const testBody: FakeGeneration = {
  initialSerie: {
    blockStartNumber: blockNumber,
    blockSeriesLength: 1,
    block: {
      // here we put the number of the block we want to customize and information related to it
      [blockNumber]: {
        hash: forkedHash,
        txLength: 6,
        txConfig: {
          // this index represent the transactionIndex in the block
          1: {
            // models can be customized, you can see the documentation further down about it
            rcptModel: 'error:notFound',
            TxType: ItemType.VALID_ITEM,
            RcptType: ItemType.ERROR_ITEM,
            LogType: ItemType.VALID_ITEM,
          }
        },
      }
    }
  },
  forkSerie: {
    blockStartNumber: blockNumber,
    blockSeriesLength: 1,
    block: {
      [blockNumber]: {
      hash: validHash,
      txLength: 6,
      txConfig: {}, // will create only valid item
      }
    }
  },
}
await fetch(rpcUrl, {
  method: "PUT",
  body: JSON.stringify(testBody),
})
  1. Large data set

There is a problem when you try to generate data with more than 100k transactions, the memory get saturated and the generation is very slow. As of now we are signing all transaction which slow things down but we also prevent the endpoint from sending the full object results as it provoke some oom. Intead you will receive a warning

{ warning: 'data is too large to stringify' }

2. HTTP Server

The core of the service, the HTTP server reads the data previously generated and sends it back according to basic configurations you provide during creation. We've kept the structure as simple as possible, opting to split the fake data you create by URL. This approach enables multiple scenarios based on the URL you call, facilitating concurrent testing.

To initiate the server, you should invoke the default exported function, as demonstrated in the example below. We've also included a hook example that allows you to introduce delays or perform other actions, although it is not mandatory.

import { evmMockServer, evmMockUtils } from '@starton/evm-mock-server';
// start a simple server
const serverRpc = await evmMockServer(55001);

// start a server and whenever a client call the endpoint /unique, delay the answer for 1000ms
// It might help you debug the data you send to the server as well
const serverRpc = await evmMockServer(55001, {
  PreResponse: async (request: IncomingMessage, body: JSONRPC | JSONRPC[], data?: FakeData) => {
    if (request.url === '/unique') {
      console.log('in unique call ', body)
      await evmMockUtils.waitFor(1000);
    }
  }
})

The http server simulate RPC method with the POST method, once a method is called on a url. It also handle multicall if you pass all your calls as array The heart of this part is the function getResponse found in server-response.ts

This part rely on a few variables present in the fakeData interface.

interface FakeData {
  blocks: Record<string, any>,// Contains information about blocks <blockHash, blockData>
  transactions: Record<string, any>; // Stores details of transactions <txHash, txkData>
  receipts: Record<string, any>; // Holds receipt data <txHash, rcptData>
  blockByNumber: Record<string, string>; // Maps block numbers to their corresponding hashes
  replaceBlock?: Record<string, string>; // Used for simulating forks by replacing block hashes
  replaceType?: ReplaceType; // Indicates the type of replacement (e.g., after first read, after some time)
  blockNavigation: BlockNavigation; // Stores an array of block numbers and their index for simulating block retrieval
}

For the server part those are important to keep in mind

  • fakeData.listBlock.list this is an array containing the list of block by number, its used when we try to get the last block number or we try to recover the latest block. We use this with the fakeData.listBlock.index in order to simulate the block creating new blocks.
  • fakeData.blockByNumber the key is the block number and the value is the hash that will be displayed. The server use this to get the current block where it is suppose to be at. When we simulate a fork we just switch the hash with the one we added in fakeData.replaceBlock. This allow use to have the server call a different block by hash so it simulate a different "path" thanks to the parentHash and the hash itself being changed

In both part we wont create extensive error check because we are creating test data which can be manually tweaked if necessary and might complexify the code. The purpose of this server being only to test we don't need strict data control. This server should also never be in any production environement but just in case we still want to keep the dependencies as small as possible to avoid any unnecessary vulnerabilities with packages becoming obsolete

Blockchain Help and Information

If you are interested in how Starton can assist you in building your web3 universe, head to our documentation.

Contributing

Feel free to explore, contribute, and shape the future of EvmMockServer with us! Your feedback and collaboration are invaluable as we continue to refine and enhance this tool.

To get started, see CONTRIBUTING.md.

Please adhere to Starton's Code of Conduct.

Future plan

Please use the develop branch in order to contribute with PR

  • [ ] Create scenarios with list of block and a fork
  • [ ] Find edge cases for test
  • [ ] Test server with different latency values
  • [ ] Error when we have more than 1000 object from json length (use stream to write or res)
  • [ ] Options to sign transactions to increase speed of tx generation

License

EvmMockServer is licensed under the Apache License 2.0.

Authors