Skip to content

Commit

Permalink
Add support for the transient storage (TSTORE/TLOAD opcodes) (#192)
Browse files Browse the repository at this point in the history
* Add support for the transient storage (TSTORE/TLOAD opcodes)
  • Loading branch information
forshtat authored May 16, 2024
1 parent 3f041f3 commit 276de79
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 8 deletions.
16 changes: 13 additions & 3 deletions packages/validation-manager/src/BundlerCollectorTracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ export interface AccessInfo {
reads: { [slot: string]: string }
// count of writes.
writes: { [slot: string]: number }
// count of transient reads
transientReads: { [slot: string]: number }
// count of transient writes
transientWrites: { [slot: string]: number }
}

export interface LogInfo {
Expand Down Expand Up @@ -291,7 +295,7 @@ export function bundlerCollectorTracer (): BundlerCollectorTracer {
}
this.lastOp = opcode

if (opcode === 'SLOAD' || opcode === 'SSTORE') {
if (opcode === 'SLOAD' || opcode === 'SSTORE' || opcode === 'TLOAD' || opcode === 'TSTORE') {
const slot = toWord(log.stack.peek(0).toString(16))
const slotHex = toHex(slot)
const addr = log.contract.getAddress()
Expand All @@ -300,7 +304,9 @@ export function bundlerCollectorTracer (): BundlerCollectorTracer {
if (access == null) {
access = {
reads: {},
writes: {}
writes: {},
transientReads: {},
transientWrites: {}
}
this.currentLevel.access[addrHex] = access
}
Expand All @@ -310,8 +316,12 @@ export function bundlerCollectorTracer (): BundlerCollectorTracer {
if (access.reads[slotHex] == null && access.writes[slotHex] == null) {
access.reads[slotHex] = toHex(db.getState(addr, slot))
}
} else {
} else if (opcode === 'SSTORE') {
this.countSlot(access.writes, slotHex)
} else if (opcode === 'TLOAD') {
this.countSlot(access.transientReads, slotHex)
} else if (opcode === 'TSTORE') {
this.countSlot(access.transientWrites, slotHex)
}
}

Expand Down
20 changes: 15 additions & 5 deletions packages/validation-manager/src/TracerResultParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,9 @@ export function tracerResultParser (

Object.entries(access).forEach(([addr, {
reads,
writes
writes,
transientReads,
transientWrites
}]) => {
// testing read/write access on contract "addr"
if (addr === sender) {
Expand Down Expand Up @@ -305,7 +307,12 @@ export function tracerResultParser (
// scan all slots. find a referenced slot
// at the end of the scan, we will check if the entity has stake, and report that slot if not.
let requireStakeSlot: string | undefined
[...Object.keys(writes), ...Object.keys(reads)].forEach(slot => {
[
...Object.keys(writes),
...Object.keys(reads),
...Object.keys(transientWrites),
...Object.keys(transientReads)
].forEach(slot => {
// slot associated with sender is allowed (e.g. token.balanceOf(sender)
// but during initial UserOp (where there is an initCode), it is allowed only for staked entity
if (associatedWith(slot, sender, entitySlots)) {
Expand All @@ -324,14 +331,17 @@ export function tracerResultParser (
// [STO-031]
// accessing storage member of entity itself requires stake.
requireStakeSlot = slot
} else if (writes[slot] == null) {
} else if (writes[slot] == null && transientWrites[slot] == null) {
// [STO-033]: staked entity have read-only access to any storage in non-entity contract.
requireStakeSlot = slot
} else {
// accessing arbitrary storage of another contract is not allowed
const readWrite = Object.keys(writes).includes(addr) ? 'write to' : 'read from'
const isWrite = Object.keys(writes).includes(slot) || Object.keys(transientWrites).includes(slot)
const isTransient = Object.keys(transientReads).includes(slot) || Object.keys(transientWrites).includes(slot)
const readWrite = isWrite ? 'write to' : 'read from'
const transientStr = isTransient ? 'transient ' : ''
requireCond(false,
`${entityTitle} has forbidden ${readWrite} ${nameAddr(addr, entityTitle)} slot ${slot}`,
`${entityTitle} has forbidden ${readWrite} ${transientStr}${nameAddr(addr, entityTitle)} slot ${slot}`,
ValidationErrors.OpcodeValidation, { [entityTitle]: entStakes?.addr })
}
})
Expand Down

0 comments on commit 276de79

Please sign in to comment.