Skip to content

Commit 028e1ee

Browse files
committed
Rm storageReader and move logic to stateManager
1 parent 3e9a91f commit 028e1ee

12 files changed

+151
-159
lines changed

lib/evm/interpreter.ts

+2-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
} from 'ethereumjs-util'
1010
import Account from 'ethereumjs-account'
1111
import { VmError, ERROR } from '../exceptions'
12-
import { StorageReader } from '../state'
1312
import PStateManager from '../state/promisified'
1413
import { getPrecompile, PrecompileFunc, PrecompileResult } from './precompiles'
1514
import { OOGResult } from './precompiles/types'
@@ -86,14 +85,12 @@ export interface ExecResult {
8685
export default class Interpreter {
8786
_vm: any
8887
_state: PStateManager
89-
_storageReader: StorageReader
9088
_tx: TxContext
9189
_block: any
9290

93-
constructor(vm: any, txContext: TxContext, block: any, storageReader: StorageReader) {
91+
constructor(vm: any, txContext: TxContext, block: any) {
9492
this._vm = vm
9593
this._state = new PStateManager(this._vm.stateManager)
96-
this._storageReader = storageReader || new StorageReader(this._state._wrapped)
9794
this._tx = txContext
9895
this._block = block
9996
}
@@ -270,8 +267,7 @@ export default class Interpreter {
270267
}
271268

272269
const loop = new Loop(this._vm, eei)
273-
const opts = Object.assign({ storageReader: this._storageReader }, loopOpts)
274-
const loopRes = await loop.run(message.code as Buffer, opts)
270+
const loopRes = await loop.run(message.code as Buffer, loopOpts)
275271

276272
let result = eei._result
277273
let gasUsed = message.gasLimit.sub(eei._gasLeft)

lib/evm/loop.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import BN = require('bn.js')
22
import Common from 'ethereumjs-common'
3-
import { StateManager, StorageReader } from '../state'
3+
import { StateManager } from '../state'
44
import PStateManager from '../state/promisified'
55
import { ERROR, VmError } from '../exceptions'
66
import Memory from './memory'
@@ -13,7 +13,6 @@ export type IsException = 0 | 1
1313

1414
export interface RunOpts {
1515
pc?: number
16-
storageReader?: StorageReader
1716
}
1817

1918
export interface RunState {
@@ -27,7 +26,6 @@ export interface RunState {
2726
validJumps: number[]
2827
_common: Common
2928
stateManager: StateManager
30-
storageReader: StorageReader
3129
eei: EEI
3230
}
3331

@@ -59,7 +57,6 @@ export default class Loop {
5957
// TODO: Replace with EEI methods
6058
_common: this._vm._common,
6159
stateManager: this._state._wrapped,
62-
storageReader: new StorageReader(this._state._wrapped),
6360
eei: this._eei,
6461
}
6562
}
@@ -69,7 +66,6 @@ export default class Loop {
6966
code: code,
7067
programCounter: opts.pc || this._runState.programCounter,
7168
validJumps: this._getValidJumpDests(code),
72-
storageReader: opts.storageReader || this._runState.storageReader,
7369
})
7470

7571
// Check that the programCounter is in range

lib/evm/opFns.ts

+16-6
Original file line numberDiff line numberDiff line change
@@ -892,15 +892,25 @@ function maxCallGas(gasLimit: BN, gasLeft: BN): BN {
892892

893893
function getContractStorage(runState: RunState, address: Buffer, key: Buffer) {
894894
return new Promise((resolve, reject) => {
895-
const cb = (err: Error, res: any) => {
895+
const cb = (err: Error | null, res: any) => {
896896
if (err) return reject(err)
897897
resolve(res)
898898
}
899-
if (runState._common.hardfork() === 'constantinople') {
900-
runState.storageReader.getContractStorage(address, key, cb)
901-
} else {
902-
runState.stateManager.getContractStorage(address, key, cb)
903-
}
899+
runState.stateManager.getContractStorage(address, key, (err: Error, current: Buffer) => {
900+
if (err) return cb(err, null)
901+
if (runState._common.hardfork() === 'constantinople') {
902+
runState.stateManager.getOriginalContractStorage(
903+
address,
904+
key,
905+
(err: Error, original: Buffer) => {
906+
if (err) return cb(err, null)
907+
cb(null, { current, original })
908+
},
909+
)
910+
} else {
911+
cb(null, current)
912+
}
913+
})
904914
})
905915
}
906916

lib/runCall.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import BN = require('bn.js')
22
import { zeros } from 'ethereumjs-util'
33
import VM from './index'
4-
import { StorageReader } from './state'
54
import TxContext from './evm/txContext'
65
import Message from './evm/message'
76
import { default as Interpreter, InterpreterResult } from './evm/interpreter'
@@ -12,7 +11,6 @@ const Block = require('ethereumjs-block')
1211
*/
1312
export interface RunCallOpts {
1413
block?: any
15-
storageReader?: StorageReader
1614
gasPrice?: Buffer
1715
origin?: Buffer
1816
caller?: Buffer
@@ -48,7 +46,6 @@ export interface RunCallCb {
4846
*/
4947
export default function runCall(this: VM, opts: RunCallOpts, cb: RunCallCb): void {
5048
const block = opts.block || new Block()
51-
const storageReader = opts.storageReader || new StorageReader(this.stateManager)
5249

5350
const txContext = new TxContext(
5451
opts.gasPrice || Buffer.alloc(0),
@@ -69,7 +66,7 @@ export default function runCall(this: VM, opts: RunCallOpts, cb: RunCallCb): voi
6966
delegatecall: opts.delegatecall || false,
7067
})
7168

72-
const interpreter = new Interpreter(this, txContext, block, storageReader)
69+
const interpreter = new Interpreter(this, txContext, block)
7370
interpreter
7471
.executeMessage(message)
7572
.then(results => cb(null, results))

lib/runCode.ts

+1-7
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import VM from './index'
1616
import TxContext from './evm/txContext'
1717
import Message from './evm/message'
1818
import { default as Interpreter, ExecResult } from './evm/interpreter'
19-
import { StorageReader } from './state'
2019
const Block = require('ethereumjs-block')
2120

2221
/**
@@ -27,7 +26,6 @@ export interface RunCodeOpts {
2726
* The [`Block`](https://github.com/ethereumjs/ethereumjs-block) the `tx` belongs to. If omitted a blank block will be used
2827
*/
2928
block?: any
30-
storageReader?: StorageReader
3129
interpreter?: Interpreter
3230
txContext?: TxContext
3331
gasPrice?: Buffer
@@ -88,10 +86,6 @@ export default function runCode(this: VM, opts: RunCodeOpts, cb: RunCodeCb): voi
8886
opts.block = new Block()
8987
}
9088

91-
if (!opts.storageReader) {
92-
opts.storageReader = new StorageReader(this.stateManager)
93-
}
94-
9589
// Backwards compatibility
9690
if (!opts.txContext) {
9791
opts.txContext = new TxContext(
@@ -115,7 +109,7 @@ export default function runCode(this: VM, opts: RunCodeOpts, cb: RunCodeCb): voi
115109

116110
let interpreter = opts.interpreter
117111
if (!interpreter) {
118-
interpreter = new Interpreter(this, opts.txContext, opts.block, opts.storageReader)
112+
interpreter = new Interpreter(this, opts.txContext, opts.block)
119113
}
120114

121115
interpreter

lib/runTx.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import Bloom from './bloom'
66
import { default as Interpreter, InterpreterResult } from './evm/interpreter'
77
import Message from './evm/message'
88
import TxContext from './evm/txContext'
9-
import { StorageReader } from './state'
109
import PStateManager from './state/promisified'
1110
const Block = require('ethereumjs-block')
1211

@@ -157,8 +156,8 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise<RunTxResult> {
157156
value: tx.value,
158157
data: tx.data,
159158
})
160-
const storageReader = new StorageReader(this.stateManager)
161-
const interpreter = new Interpreter(this, txContext, block, storageReader)
159+
state._wrapped._clearOriginalStorageCache()
160+
const interpreter = new Interpreter(this, txContext, block)
162161
const results = (await interpreter.executeMessage(message)) as RunTxResult
163162

164163
/*

lib/state/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
export { default as StateManager } from './stateManager'
2-
export { default as StorageReader } from './storageReader'

lib/state/promisified.ts

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ export default class PStateManager {
3737
return promisify(this._wrapped.getContractStorage.bind(this._wrapped))(addr, key)
3838
}
3939

40+
getOriginalContractStorage(addr: Buffer, key: Buffer): Promise<any> {
41+
return promisify(this._wrapped.getOriginalContractStorage.bind(this._wrapped))(addr, key)
42+
}
43+
4044
putContractStorage(addr: Buffer, key: Buffer, value: Buffer): Promise<void> {
4145
return promisify(this._wrapped.putContractStorage.bind(this._wrapped))(addr, key, value)
4246
}

lib/state/stateManager.ts

+43
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export default class StateManager {
2828
_touched: Set<string>
2929
_touchedStack: Set<string>[]
3030
_checkpointCount: number
31+
_originalStorageCache: Map<string, Map<string, Buffer>>
3132

3233
/**
3334
* Instantiate the StateManager interface.
@@ -48,6 +49,7 @@ export default class StateManager {
4849
this._touched = new Set()
4950
this._touchedStack = []
5051
this._checkpointCount = 0
52+
this._originalStorageCache = new Map()
5153
}
5254

5355
/**
@@ -221,6 +223,38 @@ export default class StateManager {
221223
})
222224
}
223225

226+
/**
227+
* Caches the storage value associated with the provided `address` and `key`
228+
* on first invocation, and returns the cached (original) value from then
229+
* onwards. This is used to get the original value of a storage slot for
230+
* computing gas costs according to EIP-1283.
231+
* @param address - Address of the account to get the storage for
232+
* @param key - Key in the account's storage to get the value for
233+
*/
234+
getOriginalContractStorage(address: Buffer, key: Buffer, cb: any): void {
235+
const addressHex = address.toString('hex')
236+
const keyHex = key.toString('hex')
237+
238+
let map: Map<string, Buffer>
239+
if (!this._originalStorageCache.has(addressHex)) {
240+
map = new Map()
241+
this._originalStorageCache.set(addressHex, map)
242+
} else {
243+
map = this._originalStorageCache.get(addressHex) as Map<string, Buffer>
244+
}
245+
246+
if (map.has(keyHex)) {
247+
cb(null, map.get(keyHex))
248+
} else {
249+
this.getContractStorage(address, key, (err: Error, current: Buffer) => {
250+
if (err) return cb(err)
251+
252+
map.set(keyHex, current)
253+
cb(null, current)
254+
})
255+
}
256+
}
257+
224258
/**
225259
* Modifies the storage trie of an account
226260
* @private
@@ -582,4 +616,13 @@ export default class StateManager {
582616
},
583617
)
584618
}
619+
620+
/**
621+
* Clears the original storage cache. Refer to [[getOriginalContractStorage]]
622+
* for more explanation.
623+
* @ignore
624+
*/
625+
_clearOriginalStorageCache(): void {
626+
this._originalStorageCache = new Map()
627+
}
585628
}

lib/state/storageReader.ts

-45
This file was deleted.

0 commit comments

Comments
 (0)