65 lines
2.6 KiB
Python
65 lines
2.6 KiB
Python
# Fetches the char from calldata at position $x
|
|
macro calldatachar($x):
|
|
div(calldataload($x), 2**248)
|
|
|
|
# Fetches the next $b bytes from calldata starting at position $x
|
|
# Assumes that there is nothing important in memory at bytes 0..63
|
|
macro calldatabytes_as_int($x, $b):
|
|
~mstore(32-$b, calldataload($x))
|
|
~mload(0)
|
|
|
|
# Position in calldata
|
|
with pos = 0:
|
|
# First char in calldata
|
|
with c0 = calldatachar(0):
|
|
# The start of the array must be in 192...255 because it represents
|
|
# a list length
|
|
# Length ++ body case
|
|
if c0 < 248:
|
|
pos = 1
|
|
# Length of length ++ length ++ body case
|
|
else:
|
|
pos = (c0 - 246)
|
|
# Start position of the list (save it)
|
|
with startpos = pos:
|
|
# Start position of the previous element
|
|
with lastpos = 0:
|
|
# Keep looping until we hit the end of the input
|
|
while pos < ~calldatasize():
|
|
# Next char in calldata
|
|
with c = calldatachar(pos):
|
|
lastpos = pos
|
|
# Single byte 0x00...0x7f body case
|
|
if c < 128:
|
|
pos += 1
|
|
# Length ++ body case
|
|
elif c < 184:
|
|
pos += c - 127
|
|
# Length of length ++ length ++ body case
|
|
elif c < 192:
|
|
pos += calldatabytes_as_int(pos + 1, c - 183) + (c - 182)
|
|
|
|
# Length of new RLP list
|
|
with newlen = lastpos - startpos:
|
|
# Length ++ body case
|
|
if newlen < 56:
|
|
# Store length in the first byte
|
|
~mstore8(0, 192 + newlen)
|
|
# Copy calldata right after length
|
|
~calldatacopy(1, startpos, newlen)
|
|
# Return the hash
|
|
return(~sha3(0, 1 + newlen))
|
|
else:
|
|
# The log256 of the length (ie. length of length)
|
|
# Can't go higher than 16777216 bytes due to gas limits
|
|
with _log = if(newlen < 256, 1, if(newlen < 65536, 2, 3)):
|
|
# Store the length
|
|
~mstore(0, newlen)
|
|
# Store the length of the length right before the length
|
|
with 31minuslog = 31 - _log:
|
|
~mstore8(31minuslog, 247 + _log)
|
|
# Store the rest of the data
|
|
~calldatacopy(32, startpos, newlen)
|
|
# Return the hash
|
|
return(~sha3(31minuslog, 1 + _log + newlen))
|