Skip to content

Commit

Permalink
fix: prevent blob from duplicating subroutine body (#174)
Browse files Browse the repository at this point in the history
  • Loading branch information
barnjamin authored Jan 20, 2023
1 parent ee0cef3 commit 39e93ff
Show file tree
Hide file tree
Showing 11 changed files with 909 additions and 878 deletions.
190 changes: 91 additions & 99 deletions beaker/lib/storage/global_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,18 @@
class GlobalBlob(Blob):
def __init__(self, /, *, keys: Optional[int | list[int]] = None):
super().__init__(MAX_GLOBAL_STATE, keys=keys)
self.init_subroutines()

def zero(self) -> Expr:
"""
initializes global state of an application to all zero bytes
This allows us to be lazy later and _assume_ all the strings are the same size
"""
def init_subroutines(self):
@Subroutine(TealType.none)
def set_byte_impl(idx: Expr, byte: Expr) -> Expr:
return Seq(
(key := ScratchVar()).store(self._key(self._key_idx(idx))),
App.globalPut(
key.load(),
SetByte(App.globalGet(key.load()), self._offset_for_idx(idx), byte),
),
)

@Subroutine(TealType.none)
def zero_impl() -> Expr:
Expand All @@ -43,7 +48,7 @@ def zero_impl() -> Expr:
- // ["00"*page_size, key-1]
dup2 // ["00"*page_size, key, "00"*page_size, key]
itob // ["00"*page_size, key, "00"*page_size, itob(key)]
extract 7 1 // ["00"*page_size, key, "00"*page_size, itob(key)[-1]] get the last byte of the int
extract 7 1 // ["00"*page_size, key, "00"*page_size, itob(key)[-1]]
swap // ["00"*page_size, key, itob(key)[-1], "00"*page_size]
app_global_put // ["00"*page_size, key] (removes top 2 elements)
dup // ["00"*page_size, key-1, key-1]
Expand All @@ -55,43 +60,12 @@ def zero_impl() -> Expr:
"""
return InlineAssembly(zloop, EMPTY_PAGE, self.max_keys, type=TealType.none)

return zero_impl()

def get_byte(self, idx: Expr) -> Expr:
"""
Get a single byte from global storage of an application by index
"""

@Subroutine(TealType.uint64)
def get_byte_impl(idx: Expr) -> Expr:
return GetByte(
App.globalGet(self._key(self._key_idx(idx))), self._offset_for_idx(idx)
)

return get_byte_impl(idx)

def set_byte(self, idx: Expr, byte: Expr) -> Expr:
"""
Set a single byte from global storage of an application by index
"""

@Subroutine(TealType.none)
def set_byte_impl(idx: Expr, byte: Expr) -> Expr:
return Seq(
(key := ScratchVar()).store(self._key(self._key_idx(idx))),
App.globalPut(
key.load(),
SetByte(App.globalGet(key.load()), self._offset_for_idx(idx), byte),
),
)

return set_byte_impl(idx, byte)

def read(self, bstart: Expr, bstop: Expr) -> Expr:
"""
read bytes between bstart and bend from global storage of an application by index
"""

@Subroutine(TealType.bytes)
def read_impl(bstart: Expr, bstop: Expr) -> Expr:
start_key = self._key_idx(bstart)
Expand All @@ -113,33 +87,22 @@ def read_impl(bstart: Expr, bstop: Expr) -> Expr:
return Seq(
buff.store(Bytes("")),
For(init, cond, incr).Do(
Seq(
start.store(If(key.load() == start_key, start_offset, Int(0))),
stop.store(
If(key.load() == stop_key, stop_offset, BLOB_PAGE_SIZE)
),
buff.store(
Concat(
buff.load(),
Substring(
App.globalGet(self._key(key.load())),
start.load(),
stop.load(),
),
)
),
)
start.store(If(key.load() == start_key, start_offset, Int(0))),
stop.store(If(key.load() == stop_key, stop_offset, BLOB_PAGE_SIZE)),
buff.store(
Concat(
buff.load(),
Substring(
App.globalGet(self._key(key.load())),
start.load(),
stop.load(),
),
)
),
),
buff.load(),
)

return read_impl(bstart, bstop)

def write(self, bstart: Expr, buff: Expr) -> Expr:
"""
write bytes between bstart and len(buff) to global storage of an application
"""

@Subroutine(TealType.none)
def write_impl(bstart: Expr, buff: Expr) -> Expr:
start_key = self._key_idx(bstart)
Expand All @@ -162,47 +125,76 @@ def write_impl(bstart: Expr, buff: Expr) -> Expr:
return Seq(
written.store(Int(0)),
For(init, cond, incr).Do(
Seq(
start.store(If(key.load() == start_key, start_offset, Int(0))),
stop.store(
If(key.load() == stop_key, stop_offset, BLOB_PAGE_SIZE)
),
App.globalPut(
self._key(key.load()),
If(
Or(
stop.load() != BLOB_PAGE_SIZE,
start.load() != Int(0),
)
) # Its a partial write
.Then(
Seq(
delta.store(stop.load() - start.load()),
Concat(
Substring(
App.globalGet(self._key(key.load())),
Int(0),
start.load(),
),
Extract(buff, written.load(), delta.load()),
Substring(
App.globalGet(self._key(key.load())),
stop.load(),
BLOB_PAGE_SIZE,
),
),
)
start.store(If(key.load() == start_key, start_offset, Int(0))),
stop.store(If(key.load() == stop_key, stop_offset, BLOB_PAGE_SIZE)),
App.globalPut(
self._key(key.load()),
If(
Or(
stop.load() != BLOB_PAGE_SIZE,
start.load() != Int(0),
)
.Else(
Seq(
delta.store(BLOB_PAGE_SIZE),
Extract(buff, written.load(), BLOB_PAGE_SIZE),
)
) # Its a partial write
.Then(
delta.store(stop.load() - start.load()),
Concat(
Substring(
App.globalGet(self._key(key.load())),
Int(0),
start.load(),
),
Extract(buff, written.load(), delta.load()),
Substring(
App.globalGet(self._key(key.load())),
stop.load(),
BLOB_PAGE_SIZE,
),
),
)
.Else(
delta.store(BLOB_PAGE_SIZE),
Extract(buff, written.load(), BLOB_PAGE_SIZE),
),
written.store(written.load() + delta.load()),
)
),
written.store(written.load() + delta.load()),
),
)

return write_impl(bstart, buff)
self.set_byte_impl = set_byte_impl
self.zero_impl = zero_impl
self.get_byte_impl = get_byte_impl
self.read_impl = read_impl
self.write_impl = write_impl

def zero(self) -> Expr:
"""
initializes global state of an application to all zero bytes
This allows us to be lazy later and _assume_ all the strings are the same size
"""
return self.zero_impl()

def get_byte(self, idx: Expr) -> Expr:
"""
Get a single byte from global storage of an application by index
"""
return self.get_byte_impl(idx)

def set_byte(self, idx: Expr, byte: Expr) -> Expr:
"""
Set a single byte from global storage of an application by index
"""
return self.set_byte_impl(idx, byte)

def read(self, bstart: Expr, bstop: Expr) -> Expr:
"""
read bytes between bstart and bend from global storage
of an application by index
"""
return self.read_impl(bstart, bstop)

def write(self, bstart: Expr, buff: Expr) -> Expr:
"""
write bytes between bstart and len(buff) to global storage of an application
"""
return self.write_impl(bstart, buff)
Loading

0 comments on commit 39e93ff

Please sign in to comment.