Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@nomicfoundation/ethereumjs-statemanager

Package Overview
Dependencies
Maintainers
2
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@nomicfoundation/ethereumjs-statemanager - npm Package Compare versions

Comparing version 1.0.5 to 2.0.0

src/ethersStateManager.ts

6

dist/baseStateManager.js

@@ -31,6 +31,4 @@ "use strict";

this.DEBUG = false;
// Safeguard if "process" is not available (browser)
if (typeof process?.env.DEBUG !== 'undefined') {
this.DEBUG = true;
}
// Skip DEBUG calls unless 'ethjs' included in environmental DEBUG variables
this.DEBUG = process?.env?.DEBUG?.includes('ethjs') ?? false;
this._debug = (0, debug_1.debug)('statemanager:statemanager');

@@ -37,0 +35,0 @@ }

/// <reference types="node" />
import { Account } from '@nomicfoundation/ethereumjs-util';
import { OrderedMap } from 'js-sdsl';
import type { Address } from '@nomicfoundation/ethereumjs-util';
import type { OrderedMapIterator } from 'js-sdsl';
export declare type getCb = (address: Address) => Promise<Account | undefined>;

@@ -16,3 +18,4 @@ export declare type putCb = (keyBuf: Buffer, accountRlp: Buffer) => Promise<void>;

export declare class Cache {
_cache: any;
_cache: OrderedMap<any, any>;
_cacheEnd: OrderedMapIterator<any, any>;
_checkpoints: any[];

@@ -57,3 +60,3 @@ _getCb: getCb;

* Marks current state of cache as checkpoint, which can
* later on be reverted or commited.
* later on be reverted or committed.
*/

@@ -83,3 +86,3 @@ checkpoint(): void;

* @param value
* @param modified - Has the value been modfied or is it coming unchanged from the trie (also used for deleted accounts)
* @param modified - Has the value been modified or is it coming unchanged from the trie (also used for deleted accounts)
* @param deleted - Delete operation on an account

@@ -86,0 +89,0 @@ * @param virtual - Account doesn't exist in the underlying trie

@@ -5,3 +5,3 @@ "use strict";

const ethereumjs_util_1 = require("@nomicfoundation/ethereumjs-util");
const Tree = require('functional-red-black-tree');
const js_sdsl_1 = require("js-sdsl");
/**

@@ -12,3 +12,4 @@ * @ignore

constructor(opts) {
this._cache = Tree();
this._cache = new js_sdsl_1.OrderedMap();
this._cacheEnd = this._cache.end();
this._getCb = opts.getCb;

@@ -43,6 +44,7 @@ this._putCb = opts.putCb;

const it = this._cache.find(keyStr);
if (it.node !== null) {
const rlp = it.value.val;
if (!it.equals(this._cacheEnd)) {
const value = it.pointer[1];
const rlp = value.val;
const account = ethereumjs_util_1.Account.fromRlpSerializedAccount(rlp);
account.virtual = it.value.virtual;
account.virtual = value.virtual;
return account;

@@ -58,4 +60,4 @@ }

const it = this._cache.find(keyStr);
if (it.node !== null) {
return it.value.deleted;
if (!it.equals(this._cacheEnd)) {
return it.pointer[1].deleted;
}

@@ -89,20 +91,19 @@ return false;

async flush() {
const it = this._cache.begin;
let next = true;
while (next) {
if (it.value?.modified === true) {
it.value.modified = false;
const keyBuf = Buffer.from(it.key, 'hex');
if (it.value.deleted === false) {
const accountRlp = it.value.val;
const it = this._cache.begin();
while (!it.equals(this._cacheEnd)) {
const value = it.pointer[1];
if (value.modified === true) {
value.modified = false;
const keyBuf = Buffer.from(it.pointer[0], 'hex');
if (value.deleted === false) {
const accountRlp = value.val;
await this._putCb(keyBuf, accountRlp);
}
else {
it.value.deleted = true;
it.value.virtual = true;
it.value.val = new ethereumjs_util_1.Account().serialize();
value.deleted = true;
value.virtual = true;
value.val = new ethereumjs_util_1.Account().serialize();
await this._deleteCb(keyBuf);
}
}
next = it.hasNext;
it.next();

@@ -113,6 +114,6 @@ }

* Marks current state of cache as checkpoint, which can
* later on be reverted or commited.
* later on be reverted or committed.
*/
checkpoint() {
this._checkpoints.push(this._cache);
this._checkpoints.push(new js_sdsl_1.OrderedMap(this._cache));
}

@@ -124,2 +125,3 @@ /**

this._cache = this._checkpoints.pop();
this._cacheEnd = this._cache.end();
}

@@ -136,3 +138,3 @@ /**

clear() {
this._cache = Tree();
this._cache.clear();
}

@@ -151,3 +153,3 @@ /**

* @param value
* @param modified - Has the value been modfied or is it coming unchanged from the trie (also used for deleted accounts)
* @param modified - Has the value been modified or is it coming unchanged from the trie (also used for deleted accounts)
* @param deleted - Delete operation on an account

@@ -158,10 +160,4 @@ * @param virtual - Account doesn't exist in the underlying trie

const keyHex = key.buf.toString('hex');
const it = this._cache.find(keyHex);
const val = value.serialize();
if (it.node !== null) {
this._cache = it.update({ val, modified, deleted, virtual });
}
else {
this._cache = this._cache.insert(keyHex, { val, modified, deleted, virtual });
}
this._cache.setElement(keyHex, { val, modified, deleted, virtual });
}

@@ -168,0 +164,0 @@ }

export { BaseStateManager } from './baseStateManager';
export { EthersStateManager, EthersStateManagerOpts } from './ethersStateManager';
export { AccountFields, StateAccess, StateManager } from './interface';
export { DefaultStateManager, Proof } from './stateManager';
//# sourceMappingURL=index.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefaultStateManager = exports.BaseStateManager = void 0;
exports.DefaultStateManager = exports.EthersStateManager = exports.BaseStateManager = void 0;
var baseStateManager_1 = require("./baseStateManager");
Object.defineProperty(exports, "BaseStateManager", { enumerable: true, get: function () { return baseStateManager_1.BaseStateManager; } });
var ethersStateManager_1 = require("./ethersStateManager");
Object.defineProperty(exports, "EthersStateManager", { enumerable: true, get: function () { return ethersStateManager_1.EthersStateManager; } });
var stateManager_1 = require("./stateManager");
Object.defineProperty(exports, "DefaultStateManager", { enumerable: true, get: function () { return stateManager_1.DefaultStateManager; } });
//# sourceMappingURL=index.js.map

@@ -6,3 +6,3 @@ /// <reference types="node" />

import type { Address, PrefixedHexString } from '@nomicfoundation/ethereumjs-util';
declare type StorageProof = {
export declare type StorageProof = {
key: PrefixedHexString;

@@ -180,3 +180,2 @@ proof: PrefixedHexString[];

}
export {};
//# sourceMappingURL=stateManager.d.ts.map

@@ -16,3 +16,3 @@ "use strict";

* will be the same as the hash of the empty trie which leads to
* misbehaviour in the underyling trie library.
* misbehaviour in the underlying trie library.
*/

@@ -19,0 +19,0 @@ const CODEHASH_PREFIX = Buffer.from('c');

{
"name": "@nomicfoundation/ethereumjs-statemanager",
"version": "1.0.5",
"version": "2.0.0",
"description": "An Ethereum statemanager implementation",

@@ -39,14 +39,34 @@ "keywords": [

"test:browser": "karma start karma.conf.js",
"test:node": "npm run tape -- tests/*.spec.ts",
"test:node": "npm run tape -- test/*.spec.ts",
"tsc": "../../config/cli/ts-compile.sh"
},
"dependencies": {
"@nomicfoundation/ethereumjs-common": "3.1.2",
"@nomicfoundation/ethereumjs-rlp": "4.0.3",
"@nomicfoundation/ethereumjs-trie": "5.0.5",
"@nomicfoundation/ethereumjs-util": "8.0.6",
"@nomicfoundation/ethereumjs-common": "4.0.0",
"@nomicfoundation/ethereumjs-rlp": "5.0.0",
"debug": "^4.3.3",
"ethereum-cryptography": "0.1.3",
"functional-red-black-tree": "^1.0.1"
"ethers": "^5.7.1",
"js-sdsl": "^4.1.4"
},
"devDependencies": {
"@nomicfoundation/ethereumjs-block": "5.0.0",
"@nomicfoundation/ethereumjs-trie": "6.0.0",
"@nomicfoundation/ethereumjs-util": "9.0.0",
"@types/node": "^16.11.7",
"@types/tape": "^4.13.2",
"debug": "^4.3.3",
"eslint": "^8.0.0",
"ethereum-cryptography": "0.1.3",
"functional-red-black-tree": "^1.0.1",
"karma": "^6.3.2",
"karma-chrome-launcher": "^3.1.0",
"karma-firefox-launcher": "^2.1.0",
"karma-tap": "^4.2.0",
"karma-typescript": "^5.5.3",
"nyc": "^15.1.0",
"standard": "^10.0.0",
"tape": "^5.3.1",
"ts-node": "^10.2.1",
"typescript": "^4.4.2"
}
}

@@ -28,5 +28,5 @@ # @ethereumjs/statemanager

The library includes a TypeScript interface `StateManager` to ensure a unified interface (e.g. when passed to the VM) as well as a concrete Trie-based implementation `DefaultStateManager`.
The library includes a TypeScript interface `StateManager` to ensure a unified interface (e.g. when passed to the VM) as well as a concrete Trie-based implementation `DefaultStateManager` as well as an `EthersStateManager` implementation that sources state and history data from an external `ethers` provider.
### Example
### `DefaultStateManager` Example

@@ -46,2 +46,46 @@ ```typescript

### `EthersStateManager`
First, a simple example of usage:
```typescript
import { Account, Address } from '@ethereumjs/util'
import { EthersStateManager } from '@ethereumjs/statemanager'
import { ethers } from 'ethers'
const provider = new ethers.providers.JsonRpcProvider('https://path.to.my.provider.com')
const stateManager = new EthersStateManager({ provider, blockTag: 500000n })
const vitalikDotEth = Address.fromString('0xd8da6bf26964af9d7eed9e03e53415d37aa96045')
const account = await stateManager.getAccount(vitalikDotEth)
console.log('Vitalik has a current ETH balance of ', account.balance)
```
The `EthersStateManager` can be be used with an `ethers` `JsonRpcProvider` or one of its subclasses. Instantiate the `VM` and pass in an `EthersStateManager` to run transactions against accounts sourced from the provider or to run blocks pulled from the provider at any specified block height.
**Note:** Usage of this StateManager can cause a heavy load regarding state request API calls, so be careful (or at least: aware) if used in combination with an Ethers provider connecting to a third-party API service like Infura!
### Points on usage:
#### Provider selection
- If you don't have access to a provider, you can use the `CloudFlareProvider` from the `@ethersproject/providers` module to get a quickstart.
- The provider you select must support the `eth_getProof`, `eth_getCode`, and `eth_getStorageAt` RPC methods.
- Not all providers support retrieving state from all block heights so refer to your provider's documentation. Trying to use a block height not supported by your provider (e.g. any block older than the last 256 for CloudFlare) will result in RPC errors when using the state manager.
#### Block Tag selection
- You have to pass a block number or `earliest` in the constructor that specifies the block height you want to pull state from.
- The `latest`/`pending` values supported by the Ethereum JSON-RPC are not supported as longer running scripts run the risk of state values changing as blocks are mined while your script is running.
- If using a very recent block as your block tag, be aware that reorgs could occur and potentially alter the state you are interacting with.
- If you want to rerun transactions from block X or run block X, you need to specify the block tag as X-1 in the state manager constructor to ensure you are pulling the state values at the point in time the transactions or block was run.
#### Potential gotchas
- The Ethers State Manager cannot compute valid state roots when running blocks as it does not have access to the entire Ethereum state trie so can not compute correct state roots, either for the account trie or for storage tries.
- If you are replaying mainnet transactions and an account or account storage is touched by multiple transactions in a block, you must replay those transactions in order (with regard to their position in that block) or calculated gas will likely be different than actual gas consumed.
#### Further reference
Refer to [this test script](./test/ethersStateManager.spec.ts) for complete examples of running transactions and blocks in the `vm` with data sourced from a provider.
## API

@@ -48,0 +92,0 @@

@@ -39,6 +39,5 @@ import { debug as createDebugLogger } from 'debug'

constructor(_opts: DefaultStateManagerOpts) {
// Safeguard if "process" is not available (browser)
if (typeof process?.env.DEBUG !== 'undefined') {
this.DEBUG = true
}
// Skip DEBUG calls unless 'ethjs' included in environmental DEBUG variables
this.DEBUG = process?.env?.DEBUG?.includes('ethjs') ?? false
this._debug = createDebugLogger('statemanager:statemanager')

@@ -45,0 +44,0 @@ }

import { Account } from '@nomicfoundation/ethereumjs-util'
import { OrderedMap } from 'js-sdsl'
import type { Address } from '@nomicfoundation/ethereumjs-util'
import type { OrderedMapIterator } from 'js-sdsl'
const Tree = require('functional-red-black-tree')
export type getCb = (address: Address) => Promise<Account | undefined>

@@ -21,3 +21,4 @@ export type putCb = (keyBuf: Buffer, accountRlp: Buffer) => Promise<void>

export class Cache {
_cache: any
_cache: OrderedMap<any, any>
_cacheEnd: OrderedMapIterator<any, any>
_checkpoints: any[]

@@ -30,3 +31,4 @@

constructor(opts: CacheOpts) {
this._cache = Tree()
this._cache = new OrderedMap()
this._cacheEnd = this._cache.end()
this._getCb = opts.getCb

@@ -65,6 +67,7 @@ this._putCb = opts.putCb

const it = this._cache.find(keyStr)
if (it.node !== null) {
const rlp = it.value.val
if (!it.equals(this._cacheEnd)) {
const value = it.pointer[1]
const rlp = value.val
const account = Account.fromRlpSerializedAccount(rlp)
;(account as any).virtual = it.value.virtual
;(account as any).virtual = value.virtual
return account

@@ -81,4 +84,4 @@ }

const it = this._cache.find(keyStr)
if (it.node !== null) {
return it.value.deleted
if (!it.equals(this._cacheEnd)) {
return it.pointer[1].deleted
}

@@ -115,20 +118,18 @@ return false

async flush(): Promise<void> {
const it = this._cache.begin
let next = true
while (next) {
if (it.value?.modified === true) {
it.value.modified = false
const keyBuf = Buffer.from(it.key, 'hex')
if (it.value.deleted === false) {
const accountRlp = it.value.val
const it = this._cache.begin()
while (!it.equals(this._cacheEnd)) {
const value = it.pointer[1]
if (value.modified === true) {
value.modified = false
const keyBuf = Buffer.from(it.pointer[0], 'hex')
if (value.deleted === false) {
const accountRlp = value.val
await this._putCb(keyBuf, accountRlp)
} else {
it.value.deleted = true
it.value.virtual = true
it.value.val = new Account().serialize()
value.deleted = true
value.virtual = true
value.val = new Account().serialize()
await this._deleteCb(keyBuf)
}
}
next = it.hasNext
it.next()

@@ -140,6 +141,6 @@ }

* Marks current state of cache as checkpoint, which can
* later on be reverted or commited.
* later on be reverted or committed.
*/
checkpoint(): void {
this._checkpoints.push(this._cache)
this._checkpoints.push(new OrderedMap(this._cache))
}

@@ -152,2 +153,3 @@

this._cache = this._checkpoints.pop()
this._cacheEnd = this._cache.end()
}

@@ -166,3 +168,3 @@

clear(): void {
this._cache = Tree()
this._cache.clear()
}

@@ -183,3 +185,3 @@

* @param value
* @param modified - Has the value been modfied or is it coming unchanged from the trie (also used for deleted accounts)
* @param modified - Has the value been modified or is it coming unchanged from the trie (also used for deleted accounts)
* @param deleted - Delete operation on an account

@@ -196,10 +198,5 @@ * @param virtual - Account doesn't exist in the underlying trie

const keyHex = key.buf.toString('hex')
const it = this._cache.find(keyHex)
const val = value.serialize()
if (it.node !== null) {
this._cache = it.update({ val, modified, deleted, virtual })
} else {
this._cache = this._cache.insert(keyHex, { val, modified, deleted, virtual })
}
this._cache.setElement(keyHex, { val, modified, deleted, virtual })
}
}
export { BaseStateManager } from './baseStateManager'
export { EthersStateManager, EthersStateManagerOpts } from './ethersStateManager'
export { AccountFields, StateAccess, StateManager } from './interface'
export { DefaultStateManager, Proof } from './stateManager'

@@ -23,3 +23,3 @@ import { RLP } from '@nomicfoundation/ethereumjs-rlp'

type StorageProof = {
export type StorageProof = {
key: PrefixedHexString

@@ -46,3 +46,3 @@ proof: PrefixedHexString[]

* will be the same as the hash of the empty trie which leads to
* misbehaviour in the underyling trie library.
* misbehaviour in the underlying trie library.
*/

@@ -49,0 +49,0 @@ const CODEHASH_PREFIX = Buffer.from('c')

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc