research/casper4/rlp_decoder.se.py

78 lines
2.5 KiB
Python
Raw Normal View History

macro calldatachar($x):
div(calldataload($x), 2**248)
macro calldatabytes_as_int($x, $b):
div(calldataload($x), 256**(32-$b))
def any():
# Positions of the values that we are changing
positions = array(256)
# Index of the next position we are adding to
positionIndex = 0
# Output data (main part)
data = string(~calldatasize() + 1024)
# Index of where we are adding data
dataPos = 0
# Can only parse lists; check the length of the list and set the index
# in calldata to the right start position
c = calldatachar(0)
if c < 192:
~invalid()
if c < 248:
if ~calldatasize() != 1 + (c - 192):
~invalid()
i = 1
else:
L = calldatabytes_as_int(i + 1, c - 247)
if ~calldatasize() != 1 + (c - 247) + L:
~invalid()
i = 1 + (c - 247)
# Main loop
while i < ~calldatasize():
# Get type (single byte, short, long)
c = calldatachar(i)
positions[positionIndex] = dataPos
positionIndex += 1
# Single byte < 0x80
if c < 128:
mstore(data + dataPos, 1)
calldatacopy(data + dataPos + 32, i, 1)
i += 1
dataPos += 33
# Short (up to 55 bytes)
elif c < 184:
mstore(data + dataPos, c - 128)
calldatacopy(data + dataPos + 32, i + 1, c - 128)
# Output could have been in single-byte format
if c == 129:
if calldatachar(i + 1) < 128:
~invalid()
i += c - 128 + 1
dataPos += (c - 128) + 32
# Long (56 or more bytes)
elif c < 192:
L = calldatabytes_as_int(i + 1, c - 183)
# Forbid leading zero byte
if calldatachar(i + 1) == 0:
~invalid()
# Forbid too short values
if L < 56:
~invalid()
mstore(data + dataPos, L)
calldatacopy(data + dataPos + 32, i + 1 + c - 183, L)
i += (c - 183) + 1 + L
dataPos += L + 32
else:
# Not handling nested arrays
~invalid()
if positionIndex > 32:
~invalid()
positions[positionIndex] = dataPos
output = string(2048)
i = 0
while i <= positionIndex:
output[i] = positions[i] + positionIndex * 32 + 32
i += 1
mcopy(output + positionIndex * 32 + 32, data, dataPos)
~return(output, positionIndex * 32 + dataPos + 32)