-
Notifications
You must be signed in to change notification settings - Fork 760
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement EIP 1153 - transient storage TLOAD 0xb3 TSTORE 0xb4 cleanup remove dead comment remove diff
- Loading branch information
Showing
11 changed files
with
474 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"name": "EIP-1153", | ||
"number": 1153, | ||
"comment": "Transient Storage", | ||
"url": "https://eips.ethereum.org/EIPS/eip-1153", | ||
"status": "Review", | ||
"minimumHardfork": "chainstart", | ||
"requiredEIPs": [], | ||
"gasConfig": {}, | ||
"gasPrices": { | ||
"tstore": { | ||
"v": 100, | ||
"d": "Base fee of the TSTORE opcode" | ||
}, | ||
"tload": { | ||
"v": 100, | ||
"d": "Base fee of the TLOAD opcode" | ||
} | ||
}, | ||
"vm": {}, | ||
"pow": {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import { Address } from 'ethereumjs-util' | ||
|
||
export interface TransientStorageOps { | ||
storage?: Map<Address, Map<string, Buffer>> | ||
changesets?: Changeset[][] | ||
} | ||
|
||
export type TStorage = Map<Address, Map<string, Buffer>> | ||
|
||
export interface Changeset { | ||
addr: Address | ||
key: Buffer | ||
prevValue: Buffer | ||
} | ||
|
||
const copyStorage = (input: TStorage): TStorage => { | ||
const map = new Map() | ||
for (const [addr, storage] of input.entries()) { | ||
const copy = new Map() | ||
for (const [key, value] of storage.entries()) { | ||
copy.set(key, Buffer.from(value)) | ||
} | ||
map.set(addr, copy) | ||
} | ||
return map | ||
} | ||
|
||
export default class TransientStorage { | ||
_storage: TStorage | ||
_changesets: Changeset[][] | ||
|
||
constructor(opts: TransientStorageOps = {}) { | ||
this._storage = opts.storage ?? new Map() | ||
this._changesets = opts.changesets ?? [[]] | ||
} | ||
|
||
private _addChangeset(changeset: Changeset) { | ||
const latest = this._changesets[this._changesets.length - 1] | ||
if (!latest) { | ||
throw new Error('no changeset initialized') | ||
} | ||
latest.push(changeset) | ||
} | ||
|
||
get(addr: Address, key: Buffer): Buffer { | ||
const map = this._storage.get(addr) | ||
if (!map) { | ||
return Buffer.alloc(32, 0x00) | ||
} | ||
const value = map.get(key.toString('hex')) | ||
if (!value) { | ||
return Buffer.alloc(32, 0x00) | ||
} | ||
return value | ||
} | ||
|
||
put(addr: Address, key: Buffer, value: Buffer) { | ||
if (!this._storage.has(addr)) { | ||
this._storage.set(addr, new Map()) | ||
} | ||
const map = this._storage.get(addr) | ||
|
||
const str = key.toString('hex') | ||
const prevValue = map?.get(str) ?? Buffer.alloc(32, 0x00) | ||
|
||
this._addChangeset({ | ||
addr, | ||
key, | ||
prevValue, | ||
}) | ||
|
||
map?.set(str, value) | ||
} | ||
|
||
revert() { | ||
const changeset = this._changesets.pop() | ||
if (!changeset) { | ||
throw new Error('cannot revert without a changeset') | ||
} | ||
for (const change of changeset) { | ||
const map = this._storage.get(change.addr) | ||
map?.set(change.key.toString('hex'), change.prevValue) | ||
} | ||
} | ||
|
||
commit(): void { | ||
// Don't allow there to be no changeset | ||
if (this._changesets.length <= 1) { | ||
throw new Error('trying to commit when not checkpointed') | ||
} | ||
this._changesets.pop() | ||
} | ||
|
||
checkpoint(): void { | ||
this._changesets.push([]) | ||
} | ||
|
||
clear(): void { | ||
this._storage = new Map() | ||
this._changesets = [[]] | ||
} | ||
|
||
copy(): TransientStorage { | ||
return new TransientStorage({ | ||
storage: copyStorage(this._storage), | ||
changesets: this._changesets.slice(), | ||
}) | ||
} | ||
} |
Oops, something went wrong.