@feelyourprotocol/statemanager 8141.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +373 -0
- package/README.md +331 -0
- package/dist/cjs/cache/account.d.ts +85 -0
- package/dist/cjs/cache/account.d.ts.map +1 -0
- package/dist/cjs/cache/account.js +252 -0
- package/dist/cjs/cache/account.js.map +1 -0
- package/dist/cjs/cache/cache.d.ts +23 -0
- package/dist/cjs/cache/cache.d.ts.map +1 -0
- package/dist/cjs/cache/cache.js +31 -0
- package/dist/cjs/cache/cache.js.map +1 -0
- package/dist/cjs/cache/caches.d.ts +19 -0
- package/dist/cjs/cache/caches.d.ts.map +1 -0
- package/dist/cjs/cache/caches.js +107 -0
- package/dist/cjs/cache/caches.js.map +1 -0
- package/dist/cjs/cache/code.d.ts +87 -0
- package/dist/cjs/cache/code.d.ts.map +1 -0
- package/dist/cjs/cache/code.js +258 -0
- package/dist/cjs/cache/code.js.map +1 -0
- package/dist/cjs/cache/index.d.ts +7 -0
- package/dist/cjs/cache/index.d.ts.map +1 -0
- package/dist/cjs/cache/index.js +23 -0
- package/dist/cjs/cache/index.js.map +1 -0
- package/dist/cjs/cache/originalStorageCache.d.ts +21 -0
- package/dist/cjs/cache/originalStorageCache.d.ts.map +1 -0
- package/dist/cjs/cache/originalStorageCache.js +52 -0
- package/dist/cjs/cache/originalStorageCache.js.map +1 -0
- package/dist/cjs/cache/storage.d.ts +101 -0
- package/dist/cjs/cache/storage.d.ts.map +1 -0
- package/dist/cjs/cache/storage.js +337 -0
- package/dist/cjs/cache/storage.js.map +1 -0
- package/dist/cjs/cache/types.d.ts +36 -0
- package/dist/cjs/cache/types.d.ts.map +1 -0
- package/dist/cjs/cache/types.js +8 -0
- package/dist/cjs/cache/types.js.map +1 -0
- package/dist/cjs/index.d.ts +8 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +24 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/merkleStateManager.d.ts +260 -0
- package/dist/cjs/merkleStateManager.d.ts.map +1 -0
- package/dist/cjs/merkleStateManager.js +616 -0
- package/dist/cjs/merkleStateManager.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/proof/index.d.ts +3 -0
- package/dist/cjs/proof/index.d.ts.map +1 -0
- package/dist/cjs/proof/index.js +19 -0
- package/dist/cjs/proof/index.js.map +1 -0
- package/dist/cjs/proof/merkle.d.ts +40 -0
- package/dist/cjs/proof/merkle.d.ts.map +1 -0
- package/dist/cjs/proof/merkle.js +182 -0
- package/dist/cjs/proof/merkle.js.map +1 -0
- package/dist/cjs/proof/rpc.d.ts +10 -0
- package/dist/cjs/proof/rpc.d.ts.map +1 -0
- package/dist/cjs/proof/rpc.js +20 -0
- package/dist/cjs/proof/rpc.js.map +1 -0
- package/dist/cjs/rpcStateManager.d.ts +162 -0
- package/dist/cjs/rpcStateManager.d.ts.map +1 -0
- package/dist/cjs/rpcStateManager.js +313 -0
- package/dist/cjs/rpcStateManager.js.map +1 -0
- package/dist/cjs/simpleStateManager.d.ts +54 -0
- package/dist/cjs/simpleStateManager.d.ts.map +1 -0
- package/dist/cjs/simpleStateManager.js +125 -0
- package/dist/cjs/simpleStateManager.js.map +1 -0
- package/dist/cjs/statefulBinaryTreeStateManager.d.ts +69 -0
- package/dist/cjs/statefulBinaryTreeStateManager.d.ts.map +1 -0
- package/dist/cjs/statefulBinaryTreeStateManager.js +576 -0
- package/dist/cjs/statefulBinaryTreeStateManager.js.map +1 -0
- package/dist/cjs/types.d.ts +92 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +3 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/util.d.ts +4 -0
- package/dist/cjs/util.d.ts.map +1 -0
- package/dist/cjs/util.js +21 -0
- package/dist/cjs/util.js.map +1 -0
- package/dist/esm/cache/account.d.ts +85 -0
- package/dist/esm/cache/account.d.ts.map +1 -0
- package/dist/esm/cache/account.js +248 -0
- package/dist/esm/cache/account.js.map +1 -0
- package/dist/esm/cache/cache.d.ts +23 -0
- package/dist/esm/cache/cache.d.ts.map +1 -0
- package/dist/esm/cache/cache.js +27 -0
- package/dist/esm/cache/cache.js.map +1 -0
- package/dist/esm/cache/caches.d.ts +19 -0
- package/dist/esm/cache/caches.d.ts.map +1 -0
- package/dist/esm/cache/caches.js +103 -0
- package/dist/esm/cache/caches.js.map +1 -0
- package/dist/esm/cache/code.d.ts +87 -0
- package/dist/esm/cache/code.d.ts.map +1 -0
- package/dist/esm/cache/code.js +254 -0
- package/dist/esm/cache/code.js.map +1 -0
- package/dist/esm/cache/index.d.ts +7 -0
- package/dist/esm/cache/index.d.ts.map +1 -0
- package/dist/esm/cache/index.js +7 -0
- package/dist/esm/cache/index.js.map +1 -0
- package/dist/esm/cache/originalStorageCache.d.ts +21 -0
- package/dist/esm/cache/originalStorageCache.d.ts.map +1 -0
- package/dist/esm/cache/originalStorageCache.js +48 -0
- package/dist/esm/cache/originalStorageCache.js.map +1 -0
- package/dist/esm/cache/storage.d.ts +101 -0
- package/dist/esm/cache/storage.d.ts.map +1 -0
- package/dist/esm/cache/storage.js +333 -0
- package/dist/esm/cache/storage.js.map +1 -0
- package/dist/esm/cache/types.d.ts +36 -0
- package/dist/esm/cache/types.d.ts.map +1 -0
- package/dist/esm/cache/types.js +5 -0
- package/dist/esm/cache/types.js.map +1 -0
- package/dist/esm/index.d.ts +8 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/merkleStateManager.d.ts +260 -0
- package/dist/esm/merkleStateManager.d.ts.map +1 -0
- package/dist/esm/merkleStateManager.js +612 -0
- package/dist/esm/merkleStateManager.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/proof/index.d.ts +3 -0
- package/dist/esm/proof/index.d.ts.map +1 -0
- package/dist/esm/proof/index.js +3 -0
- package/dist/esm/proof/index.js.map +1 -0
- package/dist/esm/proof/merkle.d.ts +40 -0
- package/dist/esm/proof/merkle.d.ts.map +1 -0
- package/dist/esm/proof/merkle.js +175 -0
- package/dist/esm/proof/merkle.js.map +1 -0
- package/dist/esm/proof/rpc.d.ts +10 -0
- package/dist/esm/proof/rpc.d.ts.map +1 -0
- package/dist/esm/proof/rpc.js +17 -0
- package/dist/esm/proof/rpc.js.map +1 -0
- package/dist/esm/rpcStateManager.d.ts +162 -0
- package/dist/esm/rpcStateManager.d.ts.map +1 -0
- package/dist/esm/rpcStateManager.js +308 -0
- package/dist/esm/rpcStateManager.js.map +1 -0
- package/dist/esm/simpleStateManager.d.ts +54 -0
- package/dist/esm/simpleStateManager.d.ts.map +1 -0
- package/dist/esm/simpleStateManager.js +121 -0
- package/dist/esm/simpleStateManager.js.map +1 -0
- package/dist/esm/statefulBinaryTreeStateManager.d.ts +69 -0
- package/dist/esm/statefulBinaryTreeStateManager.d.ts.map +1 -0
- package/dist/esm/statefulBinaryTreeStateManager.js +572 -0
- package/dist/esm/statefulBinaryTreeStateManager.js.map +1 -0
- package/dist/esm/types.d.ts +92 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/util.d.ts +4 -0
- package/dist/esm/util.d.ts.map +1 -0
- package/dist/esm/util.js +18 -0
- package/dist/esm/util.js.map +1 -0
- package/dist/tsconfig.prod.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.prod.esm.tsbuildinfo +1 -0
- package/package.json +74 -0
- package/src/cache/account.ts +277 -0
- package/src/cache/cache.ts +35 -0
- package/src/cache/caches.ts +125 -0
- package/src/cache/code.ts +277 -0
- package/src/cache/index.ts +6 -0
- package/src/cache/originalStorageCache.ts +57 -0
- package/src/cache/storage.ts +369 -0
- package/src/cache/types.ts +38 -0
- package/src/index.ts +7 -0
- package/src/merkleStateManager.ts +737 -0
- package/src/proof/index.ts +2 -0
- package/src/proof/merkle.ts +264 -0
- package/src/proof/rpc.ts +24 -0
- package/src/rpcStateManager.ts +381 -0
- package/src/simpleStateManager.ts +154 -0
- package/src/statefulBinaryTreeStateManager.ts +789 -0
- package/src/types.ts +103 -0
- package/src/util.ts +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# @ethereumjs/statemanager `v10`
|
|
2
|
+
|
|
3
|
+
[![NPM Package][statemanager-npm-badge]][statemanager-npm-link]
|
|
4
|
+
[![GitHub Issues][statemanager-issues-badge]][statemanager-issues-link]
|
|
5
|
+
[![Actions Status][statemanager-actions-badge]][statemanager-actions-link]
|
|
6
|
+
[![Code Coverage][statemanager-coverage-badge]][statemanager-coverage-link]
|
|
7
|
+
[![Discord][discord-badge]][discord-link]
|
|
8
|
+
|
|
9
|
+
| Library to provide high level access to Ethereum State |
|
|
10
|
+
| ------------------------------------------------------ |
|
|
11
|
+
|
|
12
|
+
- 🫧 Transparent state access from EVM/VM
|
|
13
|
+
- 🌴 Tree-shakeable API
|
|
14
|
+
- 👷🏼 Controlled dependency set (5 external + `@Noble` crypto)
|
|
15
|
+
- ⏳ Checkpoints + Diff-based Caches
|
|
16
|
+
- 🔌 Unified interface (for custom SMs)
|
|
17
|
+
- 🎁 3 SMs included (Merkle/Simple/RPC)
|
|
18
|
+
- 🛵 233KB bundle size (for Merkle SM) (63KB gzipped)
|
|
19
|
+
- 🏄🏾♂️ WASM-free default + Fully browser ready
|
|
20
|
+
|
|
21
|
+
## Table of Contents
|
|
22
|
+
|
|
23
|
+
- [Installation](#installation)
|
|
24
|
+
- [Getting Started](#getting-started)
|
|
25
|
+
- [MerkleStateManager](#merklestatemanager)
|
|
26
|
+
- [SimpleStateManager](#simplestatemanager)
|
|
27
|
+
- [RPCStateManager](#rpcstatemanager)
|
|
28
|
+
- [Verkle (experimental)](#verkle-state-managers-experimental)
|
|
29
|
+
- [Browser](#browser)
|
|
30
|
+
- [API](#api)
|
|
31
|
+
- [Development](#development)
|
|
32
|
+
- [EthereumJS](#ethereumjs)
|
|
33
|
+
- [License](#license)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
To obtain the latest version, simply require the project using `npm`:
|
|
39
|
+
|
|
40
|
+
```shell
|
|
41
|
+
npm install @ethereumjs/statemanager
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Getting Started
|
|
45
|
+
|
|
46
|
+
### Overview
|
|
47
|
+
|
|
48
|
+
The `StateManager` provides high-level access and manipulation methods to and for the Ethereum state, thinking in terms of accounts or contract code rather then the storage operations of the underlying data structure (e.g. a [Trie](../trie/)).
|
|
49
|
+
|
|
50
|
+
This library includes several different implementations that all implement the `StateManager` interface which is accepted by the `vm` library. These include:
|
|
51
|
+
|
|
52
|
+
- [`SimpleStateManager`](./src/simpleStateManager.ts) -a minimally functional (and dependency minimized) version of the state manager suitable for most basic EVM bytecode operations
|
|
53
|
+
- [`MerkleStateManager`](./src/stateManager.ts) - a Merkle-Patricia Trie-based `MerkleStateManager` implementation that is used by the `@ethereumjs/client` and `@ethereumjs/vm`
|
|
54
|
+
- [`RPCStateManager`](./src/rpcStateManager.ts) - a light-weight implementation that sources state and history data from an external JSON-RPC provider
|
|
55
|
+
- [`StatefulVerkleStateManager`](./src/statefulVerkleStateManager.ts) - an experimental implementation of a stateful verkle state manager
|
|
56
|
+
- [`StatelessVerkleStateManager`](./src/statelessVerkleStateManager.ts) - an experimental implementation of a "stateless" state manager that uses Verkle proofs to provide necessary state access for processing verkle-trie based blocks
|
|
57
|
+
|
|
58
|
+
It also includes a checkpoint/revert/commit mechanism to either persist or revert state changes and provides a sophisticated caching mechanism under the hood to reduce the need reading state accesses from disk.
|
|
59
|
+
|
|
60
|
+
### WASM Crypto Support
|
|
61
|
+
|
|
62
|
+
This library by default uses JavaScript implementations for the basic standard crypto primitives like hashing for underlying trie keys. See `@ethereumjs/common` [README](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/common) for instructions on how to replace with e.g. a more performant WASM implementation by using a shared `common` instance.
|
|
63
|
+
|
|
64
|
+
## `MerkleStateManager`
|
|
65
|
+
|
|
66
|
+
### Usage example
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
// ./examples/basicUsage.ts
|
|
70
|
+
|
|
71
|
+
import { MerkleStateManager } from '@ethereumjs/statemanager'
|
|
72
|
+
import { Account, Address, hexToBytes } from '@ethereumjs/util'
|
|
73
|
+
|
|
74
|
+
const main = async () => {
|
|
75
|
+
const stateManager = new MerkleStateManager()
|
|
76
|
+
const address = new Address(hexToBytes('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b'))
|
|
77
|
+
const account = new Account(BigInt(0), BigInt(1000))
|
|
78
|
+
await stateManager.checkpoint()
|
|
79
|
+
await stateManager.putAccount(address, account)
|
|
80
|
+
await stateManager.commit()
|
|
81
|
+
await stateManager.flush()
|
|
82
|
+
|
|
83
|
+
// Account at address 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b has balance 1000
|
|
84
|
+
console.log(
|
|
85
|
+
`Account at address ${address.toString()} has balance ${
|
|
86
|
+
(await stateManager.getAccount(address))?.balance
|
|
87
|
+
}`,
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
void main()
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Account, Storage and Code Caches
|
|
94
|
+
|
|
95
|
+
Starting with the v2 release and complemented by the v2.1 release the StateManager comes with a significantly more elaborate caching mechanism for account, storage and code caches.
|
|
96
|
+
|
|
97
|
+
There are now two cache options available: an unbounded cache (`CacheType.ORDERED_MAP`) for short-lived usage scenarios (this one is the default cache) and a fixed-size cache (`CacheType.LRU`) for a long-lived large cache scenario.
|
|
98
|
+
|
|
99
|
+
Caches now "survive" a flush operation and especially long-lived usage scenarios will benefit from increased performance by a growing and more "knowing" cache leading to less and less trie reads.
|
|
100
|
+
|
|
101
|
+
Have a look at the extended `CacheOptions` on how to use and leverage the new cache system.
|
|
102
|
+
|
|
103
|
+
### Instantiating from Proofs
|
|
104
|
+
|
|
105
|
+
The `MerkleStateManager` has a standalone constructor function `fromMerkleStateProof` that accepts one or more [EIP-1186](https://eips.ethereum.org/EIPS/eip-1186) [proofs](./src/stateManager.ts) and will instantiate a `MerkleStateManager` with a partial trie containing the state provided by the proof(s). Be aware that this constructor accepts the `StateManagerOpts` dictionary as a third parameter (i.e. `fromMerkleStateProof(proof, safe, opts)`).
|
|
106
|
+
|
|
107
|
+
Therefore, if you need to use a customized trie (e.g. one that does not use key hashing) or specify caching options, you can pass them in here. If you do instantiate a trie and pass it into the `createTrieFromProof` constructor, you also need to instantiate the trie using the corresponding `createStateManagerFromProof` constructor to ensure the state root matches when the proof data is added to the trie, consider an example:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const newTrie = await createTrieFromProof(proof, { useKeyHashing: false })
|
|
111
|
+
const partialSM = await fromMerkleStateProof([proof], true, {
|
|
112
|
+
trie: newTrie,
|
|
113
|
+
})
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
See below example for common usage:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
// ./examples/fromProofInstantiation.ts
|
|
120
|
+
|
|
121
|
+
import {
|
|
122
|
+
MerkleStateManager,
|
|
123
|
+
addMerkleStateProofData,
|
|
124
|
+
fromMerkleStateProof,
|
|
125
|
+
getMerkleStateProof,
|
|
126
|
+
} from '@ethereumjs/statemanager'
|
|
127
|
+
import { Address, hexToBytes } from '@ethereumjs/util'
|
|
128
|
+
|
|
129
|
+
const main = async () => {
|
|
130
|
+
// setup `stateManager` with some existing address
|
|
131
|
+
const stateManager = new MerkleStateManager()
|
|
132
|
+
const contractAddress = new Address(hexToBytes('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b'))
|
|
133
|
+
const byteCode = hexToBytes('0x67ffffffffffffffff600160006000fb')
|
|
134
|
+
const storageKey1 = hexToBytes(
|
|
135
|
+
'0x0000000000000000000000000000000000000000000000000000000000000001',
|
|
136
|
+
)
|
|
137
|
+
const storageKey2 = hexToBytes(
|
|
138
|
+
'0x0000000000000000000000000000000000000000000000000000000000000002',
|
|
139
|
+
)
|
|
140
|
+
const storageValue1 = hexToBytes('0x01')
|
|
141
|
+
const storageValue2 = hexToBytes('0x02')
|
|
142
|
+
|
|
143
|
+
await stateManager.putCode(contractAddress, byteCode)
|
|
144
|
+
await stateManager.putStorage(contractAddress, storageKey1, storageValue1)
|
|
145
|
+
await stateManager.putStorage(contractAddress, storageKey2, storageValue2)
|
|
146
|
+
|
|
147
|
+
const proof = await getMerkleStateProof(stateManager, contractAddress)
|
|
148
|
+
const proofWithStorage = await getMerkleStateProof(stateManager, contractAddress, [
|
|
149
|
+
storageKey1,
|
|
150
|
+
storageKey2,
|
|
151
|
+
])
|
|
152
|
+
const partialStateManager = await fromMerkleStateProof(proof)
|
|
153
|
+
|
|
154
|
+
// To add more proof data, use `addMerkleStateProofData`
|
|
155
|
+
await addMerkleStateProofData(partialStateManager, proofWithStorage)
|
|
156
|
+
console.log(await partialStateManager.getCode(contractAddress)) // contract bytecode is not included in proof
|
|
157
|
+
console.log(await partialStateManager.getStorage(contractAddress, storageKey1), storageValue1) // should match
|
|
158
|
+
console.log(await partialStateManager.getStorage(contractAddress, storageKey2), storageValue2) // should match
|
|
159
|
+
|
|
160
|
+
const accountFromNewSM = await partialStateManager.getAccount(contractAddress)
|
|
161
|
+
const accountFromOldSM = await stateManager.getAccount(contractAddress)
|
|
162
|
+
console.log(accountFromNewSM, accountFromOldSM) // should match
|
|
163
|
+
|
|
164
|
+
const slot1FromNewSM = await stateManager.getStorage(contractAddress, storageKey1)
|
|
165
|
+
const slot2FromNewSM = await stateManager.getStorage(contractAddress, storageKey2)
|
|
166
|
+
console.log(slot1FromNewSM, storageValue1) // should match
|
|
167
|
+
console.log(slot2FromNewSM, storageValue2) // should match
|
|
168
|
+
}
|
|
169
|
+
void main()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## `SimpleStateManager`
|
|
173
|
+
|
|
174
|
+
The `SimpleStateManager` is a dependency-minimized simple state manager implementation. While this state manager implementation lacks the implementations of some non-core functionality as well as proof related logic (e.g. `setStateRoot()`) it is suitable for a lot use cases where things like sophisticated caching or state root handling is not needed.
|
|
175
|
+
|
|
176
|
+
This state manager can be instantiated and used as follows:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
// ./examples/simple.ts
|
|
180
|
+
|
|
181
|
+
import { Account, createAddressFromPrivateKey, randomBytes } from '@ethereumjs/util'
|
|
182
|
+
|
|
183
|
+
import { SimpleStateManager } from '../src/index.ts'
|
|
184
|
+
|
|
185
|
+
const main = async () => {
|
|
186
|
+
const sm = new SimpleStateManager()
|
|
187
|
+
const address = createAddressFromPrivateKey(randomBytes(32))
|
|
188
|
+
const account = new Account(0n, 0xfffffn)
|
|
189
|
+
await sm.putAccount(address, account)
|
|
190
|
+
console.log(await sm.getAccount(address))
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
void main()
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## `RPCStateManager`
|
|
198
|
+
|
|
199
|
+
The `RPCStateManager` can be be used with any JSON-RPC provider that supports the `eth` namespace. Instantiate the `VM` and pass in an `RPCStateManager` to run transactions against accounts sourced from the provider or to run blocks pulled from the provider at any specified block height.
|
|
200
|
+
|
|
201
|
+
A simple example of usage:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
// ./examples/rpcStateManager.ts
|
|
205
|
+
|
|
206
|
+
import { RPCStateManager } from '@ethereumjs/statemanager'
|
|
207
|
+
import { createAddressFromString } from '@ethereumjs/util'
|
|
208
|
+
|
|
209
|
+
const main = async () => {
|
|
210
|
+
try {
|
|
211
|
+
const provider = 'https://path.to.my.provider.com'
|
|
212
|
+
const stateManager = new RPCStateManager({ provider, blockTag: 500000n })
|
|
213
|
+
const vitalikDotEth = createAddressFromString('0xd8da6bf26964af9d7eed9e03e53415d37aa96045')
|
|
214
|
+
const account = await stateManager.getAccount(vitalikDotEth)
|
|
215
|
+
console.log('Vitalik has a current ETH balance of ', account?.balance)
|
|
216
|
+
} catch (e) {
|
|
217
|
+
console.log(e.message) // fetch fails because provider url is not real. please replace provider with a valid rpc url string.
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
void main()
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**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 a JSON-RPC provider connecting to a third-party API service like Infura!
|
|
224
|
+
|
|
225
|
+
### Points on `RPCStateManager` usage
|
|
226
|
+
|
|
227
|
+
#### Instantiating the EVM
|
|
228
|
+
|
|
229
|
+
In order to have an EVM instance that supports the BLOCKHASH opcode (which requires access to block history), you must instantiate both the `RPCStateManager` and the `RpcBlockChain` and use that when initializing your EVM instance as below:
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
// ./examples/evm.ts
|
|
233
|
+
|
|
234
|
+
import { createEVM } from '@ethereumjs/evm'
|
|
235
|
+
import { RPCBlockChain, RPCStateManager } from '@ethereumjs/statemanager'
|
|
236
|
+
|
|
237
|
+
const main = async () => {
|
|
238
|
+
try {
|
|
239
|
+
const provider = 'https://path.to.my.provider.com'
|
|
240
|
+
const blockchain = new RPCBlockChain(provider)
|
|
241
|
+
const blockTag = 1n
|
|
242
|
+
const state = new RPCStateManager({ provider, blockTag })
|
|
243
|
+
const evm = await createEVM({ blockchain, stateManager: state }) // note that evm is ready to run BLOCKHASH opcodes (over RPC)
|
|
244
|
+
} catch (e) {
|
|
245
|
+
console.log(e.message) // fetch would fail because provider url is not real. please replace provider with a valid RPC url string.
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
void main()
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Note: Failing to provide the `RPCBlockChain` instance when instantiating the EVM means that the `BLOCKHASH` opcode will fail to work correctly during EVM execution.
|
|
252
|
+
|
|
253
|
+
#### Provider selection
|
|
254
|
+
|
|
255
|
+
- The provider you select must support the `eth_getProof`, `eth_getCode`, and `eth_getStorageAt` RPC methods.
|
|
256
|
+
- 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.
|
|
257
|
+
|
|
258
|
+
#### Block Tag selection
|
|
259
|
+
|
|
260
|
+
- You have to pass a block number or `earliest` in the constructor that specifies the block height you want to pull state from.
|
|
261
|
+
- 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.
|
|
262
|
+
- 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.
|
|
263
|
+
- 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.
|
|
264
|
+
|
|
265
|
+
#### Potential gotchas
|
|
266
|
+
|
|
267
|
+
- The RPC 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.
|
|
268
|
+
- 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.
|
|
269
|
+
|
|
270
|
+
#### Further reference
|
|
271
|
+
|
|
272
|
+
Refer to [this test script](./test/rpcStateManager.spec.ts) for complete examples of running transactions and blocks in the `vm` with data sourced from a provider.
|
|
273
|
+
|
|
274
|
+
## Verkle (experimental)
|
|
275
|
+
|
|
276
|
+
There are two new verkle related state managers integrated into the code base. These state managers are very experimental and meant to be used for connecting to early [Verkle Tree](https://eips.ethereum.org/EIPS/eip-6800) test networks (Kaustinen). These state managers are not yet sufficiently tested and APIs are not yet stable and it therefore should not be used in production.
|
|
277
|
+
|
|
278
|
+
See [PRs around Verkle](https://github.com/search?q=repo%3Aethereumjs%2Fethereumjs-monorepo+verkle&type=pullrequests) in our monorepo for an entrypoint if you are interested in our current Verkle related work.
|
|
279
|
+
|
|
280
|
+
## Browser
|
|
281
|
+
|
|
282
|
+
We provide hybrid ESM/CJS builds for all our libraries. With the v10 breaking release round from Spring 2025, all libraries are "pure-JS" by default and we have eliminated all hard-wired WASM code. Additionally we have substantially lowered the bundle sizes, reduced the number of dependencies, and cut out all usages of Node.js-specific primitives (like the Node.js event emitter).
|
|
283
|
+
|
|
284
|
+
It is easily possible to run a browser build of one of the EthereumJS libraries within a modern browser using the provided ESM build. For a setup example see [./examples/browser.html](./examples/browser.html).
|
|
285
|
+
|
|
286
|
+
## API
|
|
287
|
+
|
|
288
|
+
### Docs
|
|
289
|
+
|
|
290
|
+
Generated TypeDoc API [Documentation](./docs/README.md)
|
|
291
|
+
|
|
292
|
+
### Hybrid CJS/ESM Builds
|
|
293
|
+
|
|
294
|
+
With the breaking releases from Summer 2023 we have started to ship our libraries with both CommonJS (`cjs` folder) and ESM builds (`esm` folder), see `package.json` for the detailed setup.
|
|
295
|
+
|
|
296
|
+
If you use an ES6-style `import` in your code files from the ESM build will be used:
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
import { EthereumJSClass } from '@ethereumjs/[PACKAGE_NAME]'
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
If you use Node.js specific `require`, the CJS build will be used:
|
|
303
|
+
|
|
304
|
+
```ts
|
|
305
|
+
const { EthereumJSClass } = require('@ethereumjs/[PACKAGE_NAME]')
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Using ESM will give you additional advantages over CJS beyond browser usage like static code analysis / Tree Shaking which CJS can not provide.
|
|
309
|
+
|
|
310
|
+
## Development
|
|
311
|
+
|
|
312
|
+
Developer documentation - currently mainly with information on testing and debugging - can be found [here](./DEVELOPER.md).
|
|
313
|
+
|
|
314
|
+
## EthereumJS
|
|
315
|
+
|
|
316
|
+
The `EthereumJS` GitHub organization and its repositories are managed by members of the former Ethereum Foundation JavaScript team and the broader Ethereum community. If you want to join for work or carry out improvements on the libraries see the [developer docs](../../DEVELOPER.md) for an overview of current standards and tools and review our [code of conduct](../../CODE_OF_CONDUCT.md).
|
|
317
|
+
|
|
318
|
+
## License
|
|
319
|
+
|
|
320
|
+
[MPL-2.0](<https://tldrlegal.com/license/mozilla-public-license-2.0-(mpl-2)>)
|
|
321
|
+
|
|
322
|
+
[discord-badge]: https://img.shields.io/static/v1?logo=discord&label=discord&message=Join&color=blue
|
|
323
|
+
[discord-link]: https://discord.gg/TNwARpR
|
|
324
|
+
[statemanager-npm-badge]: https://img.shields.io/npm/v/@ethereumjs/statemanager.svg
|
|
325
|
+
[statemanager-npm-link]: https://www.npmjs.com/package/@ethereumjs/statemanager
|
|
326
|
+
[statemanager-issues-badge]: https://img.shields.io/github/issues/ethereumjs/ethereumjs-monorepo/package:%20statemanager?label=issues
|
|
327
|
+
[statemanager-issues-link]: https://github.com/ethereumjs/ethereumjs-monorepo/issues?q=is%3Aopen+is%3Aissue+label%3A"package%3A+statemanager"
|
|
328
|
+
[statemanager-actions-badge]: https://github.com/ethereumjs/ethereumjs-monorepo/workflows/StateManager/badge.svg
|
|
329
|
+
[statemanager-actions-link]: https://github.com/ethereumjs/ethereumjs-monorepo/actions?query=workflow%3A%22Statemanager%22
|
|
330
|
+
[statemanager-coverage-badge]: https://codecov.io/gh/ethereumjs/ethereumjs-monorepo/branch/master/graph/badge.svg?flag=statemanager
|
|
331
|
+
[statemanager-coverage-link]: https://codecov.io/gh/ethereumjs/ethereumjs-monorepo/tree/master/packages/statemanager
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { OrderedMap } from '@js-sdsl/ordered-map';
|
|
2
|
+
import { LRUCache } from 'lru-cache';
|
|
3
|
+
import { Cache } from './cache.ts';
|
|
4
|
+
import type { Account, Address } from '@feelyourprotocol/util';
|
|
5
|
+
import type { CacheOpts } from './types.ts';
|
|
6
|
+
/**
|
|
7
|
+
* account: undefined
|
|
8
|
+
*
|
|
9
|
+
* Account is known to not exist in the trie
|
|
10
|
+
*/
|
|
11
|
+
type AccountCacheElement = {
|
|
12
|
+
accountRLP: Uint8Array | undefined;
|
|
13
|
+
};
|
|
14
|
+
export declare class AccountCache extends Cache {
|
|
15
|
+
_lruCache: LRUCache<string, AccountCacheElement> | undefined;
|
|
16
|
+
_orderedMapCache: OrderedMap<string, AccountCacheElement> | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Diff cache collecting the state of the cache
|
|
19
|
+
* at the beginning of checkpoint height
|
|
20
|
+
* (respectively: before a first modification)
|
|
21
|
+
*
|
|
22
|
+
* If the whole cache element is undefined (in contrast
|
|
23
|
+
* to the account), the element didn't exist in the cache
|
|
24
|
+
* before.
|
|
25
|
+
*/
|
|
26
|
+
_diffCache: Map<string, AccountCacheElement | undefined>[];
|
|
27
|
+
constructor(opts: CacheOpts);
|
|
28
|
+
_saveCachePreState(cacheKeyHex: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* Puts account to cache under its address.
|
|
31
|
+
* @param address - Address of account
|
|
32
|
+
* @param account - Account or undefined if account doesn't exist in the trie
|
|
33
|
+
*/
|
|
34
|
+
put(address: Address, account: Account | undefined, couldBePartialAccount?: boolean): void;
|
|
35
|
+
/**
|
|
36
|
+
* Returns the queried account or undefined if account doesn't exist
|
|
37
|
+
* @param address - Address of account
|
|
38
|
+
*/
|
|
39
|
+
get(address: Address): AccountCacheElement | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Marks address as deleted in cache.
|
|
42
|
+
* @param address - Address
|
|
43
|
+
*/
|
|
44
|
+
del(address: Address): void;
|
|
45
|
+
/**
|
|
46
|
+
* Flushes cache by returning accounts that have been modified
|
|
47
|
+
* or deleted and resetting the diff cache (at checkpoint height).
|
|
48
|
+
*/
|
|
49
|
+
flush(): [string, AccountCacheElement][];
|
|
50
|
+
/**
|
|
51
|
+
* Revert changes to cache last checkpoint (no effect on trie).
|
|
52
|
+
*/
|
|
53
|
+
revert(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Commits to current state of cache (no effect on trie).
|
|
56
|
+
*/
|
|
57
|
+
commit(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Marks current state of cache as checkpoint, which can
|
|
60
|
+
* later on be reverted or committed.
|
|
61
|
+
*/
|
|
62
|
+
checkpoint(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Returns the size of the cache
|
|
65
|
+
* @returns
|
|
66
|
+
*/
|
|
67
|
+
size(): number;
|
|
68
|
+
/**
|
|
69
|
+
* Returns a dict with cache stats
|
|
70
|
+
* @param reset
|
|
71
|
+
*/
|
|
72
|
+
stats(reset?: boolean): {
|
|
73
|
+
size: number;
|
|
74
|
+
reads: number;
|
|
75
|
+
hits: number;
|
|
76
|
+
writes: number;
|
|
77
|
+
deletions: number;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Clears cache.
|
|
81
|
+
*/
|
|
82
|
+
clear(): void;
|
|
83
|
+
}
|
|
84
|
+
export {};
|
|
85
|
+
//# sourceMappingURL=account.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../../src/cache/account.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAEpC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAGlC,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C;;;;GAIG;AACH,KAAK,mBAAmB,GAAG;IACzB,UAAU,EAAE,UAAU,GAAG,SAAS,CAAA;CACnC,CAAA;AAED,qBAAa,YAAa,SAAQ,KAAK;IACrC,SAAS,EAAE,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAAG,SAAS,CAAA;IAC5D,gBAAgB,EAAE,UAAU,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAAG,SAAS,CAAA;IAErE;;;;;;;;OAQG;IACH,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,GAAG,SAAS,CAAC,EAAE,CAAK;gBACnD,IAAI,EAAE,SAAS;IAe3B,kBAAkB,CAAC,WAAW,EAAE,MAAM;IAatC;;;;OAIG;IACH,GAAG,CACD,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,qBAAqB,GAAE,OAAe,GACrC,IAAI;IAwBP;;;OAGG;IACH,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,mBAAmB,GAAG,SAAS;IAoBtD;;;OAGG;IACH,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAoB3B;;;OAGG;IACH,KAAK,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,EAAE;IA0BxC;;OAEG;IACH,MAAM,IAAI,IAAI;IAyBd;;OAEG;IACH,MAAM,IAAI,IAAI;IAgBd;;;OAGG;IACH,UAAU,IAAI,IAAI;IAQlB;;;OAGG;IACH,IAAI;IAQJ;;;OAGG;IACH,KAAK,CAAC,KAAK,UAAO;;;;;;;IAelB;;OAEG;IACH,KAAK,IAAI,IAAI;CAUd"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AccountCache = void 0;
|
|
4
|
+
const util_1 = require("@feelyourprotocol/util");
|
|
5
|
+
const ordered_map_1 = require("@js-sdsl/ordered-map");
|
|
6
|
+
const debug_1 = require("debug");
|
|
7
|
+
const lru_cache_1 = require("lru-cache");
|
|
8
|
+
const cache_ts_1 = require("./cache.js");
|
|
9
|
+
const types_ts_1 = require("./types.js");
|
|
10
|
+
class AccountCache extends cache_ts_1.Cache {
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
super();
|
|
13
|
+
/**
|
|
14
|
+
* Diff cache collecting the state of the cache
|
|
15
|
+
* at the beginning of checkpoint height
|
|
16
|
+
* (respectively: before a first modification)
|
|
17
|
+
*
|
|
18
|
+
* If the whole cache element is undefined (in contrast
|
|
19
|
+
* to the account), the element didn't exist in the cache
|
|
20
|
+
* before.
|
|
21
|
+
*/
|
|
22
|
+
this._diffCache = [];
|
|
23
|
+
if (opts.type === types_ts_1.CacheType.LRU) {
|
|
24
|
+
this._lruCache = new lru_cache_1.LRUCache({
|
|
25
|
+
max: opts.size,
|
|
26
|
+
updateAgeOnGet: true,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
this._orderedMapCache = new ordered_map_1.OrderedMap();
|
|
31
|
+
}
|
|
32
|
+
this._diffCache.push(new Map());
|
|
33
|
+
this._debug = (0, debug_1.default)('statemanager:cache:account');
|
|
34
|
+
}
|
|
35
|
+
_saveCachePreState(cacheKeyHex) {
|
|
36
|
+
const diffMap = this._diffCache[this._checkpoints];
|
|
37
|
+
if (!diffMap.has(cacheKeyHex)) {
|
|
38
|
+
let oldElem;
|
|
39
|
+
if (this._lruCache) {
|
|
40
|
+
oldElem = this._lruCache.get(cacheKeyHex);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
oldElem = this._orderedMapCache.getElementByKey(cacheKeyHex);
|
|
44
|
+
}
|
|
45
|
+
diffMap.set(cacheKeyHex, oldElem);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Puts account to cache under its address.
|
|
50
|
+
* @param address - Address of account
|
|
51
|
+
* @param account - Account or undefined if account doesn't exist in the trie
|
|
52
|
+
*/
|
|
53
|
+
put(address, account, couldBePartialAccount = false) {
|
|
54
|
+
// Using deprecated bytesToUnprefixedHex for performance: used as Map keys for cache lookups.
|
|
55
|
+
const addressHex = (0, util_1.bytesToUnprefixedHex)(address.bytes);
|
|
56
|
+
this._saveCachePreState(addressHex);
|
|
57
|
+
const elem = {
|
|
58
|
+
accountRLP: account !== undefined
|
|
59
|
+
? couldBePartialAccount
|
|
60
|
+
? account.serializeWithPartialInfo()
|
|
61
|
+
: account.serialize()
|
|
62
|
+
: undefined,
|
|
63
|
+
};
|
|
64
|
+
if (this.DEBUG) {
|
|
65
|
+
this._debug(`Put account ${addressHex}`);
|
|
66
|
+
}
|
|
67
|
+
if (this._lruCache) {
|
|
68
|
+
this._lruCache.set(addressHex, elem);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
this._orderedMapCache.setElement(addressHex, elem);
|
|
72
|
+
}
|
|
73
|
+
this._stats.writes += 1;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Returns the queried account or undefined if account doesn't exist
|
|
77
|
+
* @param address - Address of account
|
|
78
|
+
*/
|
|
79
|
+
get(address) {
|
|
80
|
+
// Using deprecated bytesToUnprefixedHex for performance: used as Map keys for cache lookups.
|
|
81
|
+
const addressHex = (0, util_1.bytesToUnprefixedHex)(address.bytes);
|
|
82
|
+
if (this.DEBUG) {
|
|
83
|
+
this._debug(`Get account ${addressHex}`);
|
|
84
|
+
}
|
|
85
|
+
let elem;
|
|
86
|
+
if (this._lruCache) {
|
|
87
|
+
elem = this._lruCache.get(addressHex);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
elem = this._orderedMapCache.getElementByKey(addressHex);
|
|
91
|
+
}
|
|
92
|
+
this._stats.reads += 1;
|
|
93
|
+
if (elem) {
|
|
94
|
+
this._stats.hits += 1;
|
|
95
|
+
}
|
|
96
|
+
return elem;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Marks address as deleted in cache.
|
|
100
|
+
* @param address - Address
|
|
101
|
+
*/
|
|
102
|
+
del(address) {
|
|
103
|
+
// Using deprecated bytesToUnprefixedHex for performance: used as Map keys for cache lookups.
|
|
104
|
+
const addressHex = (0, util_1.bytesToUnprefixedHex)(address.bytes);
|
|
105
|
+
this._saveCachePreState(addressHex);
|
|
106
|
+
if (this.DEBUG) {
|
|
107
|
+
this._debug(`Delete account ${addressHex}`);
|
|
108
|
+
}
|
|
109
|
+
if (this._lruCache) {
|
|
110
|
+
this._lruCache.set(addressHex, {
|
|
111
|
+
accountRLP: undefined,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
this._orderedMapCache.setElement(addressHex, {
|
|
116
|
+
accountRLP: undefined,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
this._stats.deletions += 1;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Flushes cache by returning accounts that have been modified
|
|
123
|
+
* or deleted and resetting the diff cache (at checkpoint height).
|
|
124
|
+
*/
|
|
125
|
+
flush() {
|
|
126
|
+
if (this.DEBUG) {
|
|
127
|
+
this._debug(`Flushing cache on checkpoint ${this._checkpoints}`);
|
|
128
|
+
}
|
|
129
|
+
const diffMap = this._diffCache[this._checkpoints];
|
|
130
|
+
const items = [];
|
|
131
|
+
for (const entry of diffMap.entries()) {
|
|
132
|
+
const cacheKeyHex = entry[0];
|
|
133
|
+
let elem;
|
|
134
|
+
if (this._lruCache) {
|
|
135
|
+
elem = this._lruCache.get(cacheKeyHex);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
elem = this._orderedMapCache.getElementByKey(cacheKeyHex);
|
|
139
|
+
}
|
|
140
|
+
if (elem !== undefined) {
|
|
141
|
+
items.push([cacheKeyHex, elem]);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
this._diffCache[this._checkpoints] = new Map();
|
|
145
|
+
return items;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Revert changes to cache last checkpoint (no effect on trie).
|
|
149
|
+
*/
|
|
150
|
+
revert() {
|
|
151
|
+
this._checkpoints -= 1;
|
|
152
|
+
if (this.DEBUG) {
|
|
153
|
+
this._debug(`Revert to checkpoint ${this._checkpoints}`);
|
|
154
|
+
}
|
|
155
|
+
const diffMap = this._diffCache.pop();
|
|
156
|
+
for (const entry of diffMap.entries()) {
|
|
157
|
+
const addressHex = entry[0];
|
|
158
|
+
const elem = entry[1];
|
|
159
|
+
if (elem === undefined) {
|
|
160
|
+
if (this._lruCache) {
|
|
161
|
+
this._lruCache.delete(addressHex);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
this._orderedMapCache.eraseElementByKey(addressHex);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
if (this._lruCache) {
|
|
169
|
+
this._lruCache.set(addressHex, elem);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
this._orderedMapCache.setElement(addressHex, elem);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Commits to current state of cache (no effect on trie).
|
|
179
|
+
*/
|
|
180
|
+
commit() {
|
|
181
|
+
this._checkpoints -= 1;
|
|
182
|
+
if (this.DEBUG) {
|
|
183
|
+
this._debug(`Commit to checkpoint ${this._checkpoints}`);
|
|
184
|
+
}
|
|
185
|
+
const diffMap = this._diffCache.pop();
|
|
186
|
+
for (const entry of diffMap.entries()) {
|
|
187
|
+
const addressHex = entry[0];
|
|
188
|
+
const oldEntry = this._diffCache[this._checkpoints].has(addressHex);
|
|
189
|
+
if (!oldEntry) {
|
|
190
|
+
const elem = entry[1];
|
|
191
|
+
this._diffCache[this._checkpoints].set(addressHex, elem);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Marks current state of cache as checkpoint, which can
|
|
197
|
+
* later on be reverted or committed.
|
|
198
|
+
*/
|
|
199
|
+
checkpoint() {
|
|
200
|
+
this._checkpoints += 1;
|
|
201
|
+
if (this.DEBUG) {
|
|
202
|
+
this._debug(`New checkpoint ${this._checkpoints}`);
|
|
203
|
+
}
|
|
204
|
+
this._diffCache.push(new Map());
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Returns the size of the cache
|
|
208
|
+
* @returns
|
|
209
|
+
*/
|
|
210
|
+
size() {
|
|
211
|
+
if (this._lruCache) {
|
|
212
|
+
return this._lruCache.size;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
return this._orderedMapCache.size();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Returns a dict with cache stats
|
|
220
|
+
* @param reset
|
|
221
|
+
*/
|
|
222
|
+
stats(reset = true) {
|
|
223
|
+
const stats = { ...this._stats };
|
|
224
|
+
stats.size = this.size();
|
|
225
|
+
if (reset) {
|
|
226
|
+
this._stats = {
|
|
227
|
+
size: 0,
|
|
228
|
+
reads: 0,
|
|
229
|
+
hits: 0,
|
|
230
|
+
writes: 0,
|
|
231
|
+
deletions: 0,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
return stats;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Clears cache.
|
|
238
|
+
*/
|
|
239
|
+
clear() {
|
|
240
|
+
if (this.DEBUG) {
|
|
241
|
+
this._debug(`Clear cache`);
|
|
242
|
+
}
|
|
243
|
+
if (this._lruCache) {
|
|
244
|
+
this._lruCache.clear();
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
this._orderedMapCache.clear();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
exports.AccountCache = AccountCache;
|
|
252
|
+
//# sourceMappingURL=account.js.map
|