Skip to content

Commit 9129829

Browse files
committed
Refactor abi encoding and decoding
1 parent 53630ec commit 9129829

4 files changed

Lines changed: 53 additions & 22 deletions

File tree

example/storage.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
if args.action == 'set':
3030
user = pleth.wallet.Wallet(int(args.prikey, 0))
3131
data = pleth.abi.function_selector('set', ['uint256']) + pleth.abi.argument_encoding([
32-
pleth.abi.encode_uint256(42),
32+
pleth.abi.Uint256.encode(42),
3333
])
3434
hash = user.contract_exec(bytearray.fromhex(args.addr[2:]), 0, data)
3535
print(f'hash = 0x{hash.hex()}')

pleth/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from . import core
44
from . import denomination
55
from . import ecdsa
6+
from . import io
67
from . import keccak
78
from . import objectdict
89
from . import rate

pleth/abi.py

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import io
12
import pleth.core
3+
import pleth.io
24

35
# The Contract Application Binary Interface (ABI) is the standard way to interact with contracts in the Ethereum
46
# ecosystem, both from outside the blockchain and for contract-to-contract interaction. Data is encoded according to
@@ -8,27 +10,6 @@
810
# See: https://docs.soliditylang.org/en/latest/abi-spec.html
911

1012

11-
def encode_uint256(data: int) -> bytearray:
12-
assert data >= 0
13-
assert data <= 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
14-
return bytearray(data.to_bytes(32))
15-
16-
17-
def decode_uint256(data: bytearray) -> int:
18-
assert len(data) == 32
19-
return int.from_bytes(data)
20-
21-
22-
def encode_address(data: bytearray) -> bytearray:
23-
assert len(data) == 20
24-
return bytearray(12) + data
25-
26-
27-
def decode_address(data: bytearray) -> bytearray:
28-
assert len(data) == 32
29-
return data[12:]
30-
31-
3213
def function_selector(name: str, args_type: list[str]) -> bytearray:
3314
s = name + '(' + ','.join(args_type) + ')'
3415
return pleth.core.hash(bytearray(s.encode()))[:4]
@@ -39,3 +20,40 @@ def argument_encoding(data: list[bytearray]) -> bytearray:
3920
for e in data:
4021
s.extend(e)
4122
return s
23+
24+
25+
class Address:
26+
@classmethod
27+
def decode(cls, reader: io.IOBase) -> bytearray:
28+
return pleth.io.read_full(reader, 32)[12:]
29+
30+
@classmethod
31+
def encode(cls, origin: bytearray) -> bytearray:
32+
assert len(origin) == 20
33+
return bytearray(12) + origin
34+
35+
36+
class Bytes:
37+
@classmethod
38+
def decode(cls, reader: io.IOBase) -> bytearray:
39+
length = Uint256.decode(reader)
40+
padded = (length + 31) & -32
41+
return pleth.io.read_full(reader, padded)[:length]
42+
43+
@classmethod
44+
def encode(cls, origin: bytearray) -> bytearray:
45+
length = len(origin)
46+
padded = (length + 31) & -32
47+
return Uint256.encode(length) + origin + bytearray(padded - length)
48+
49+
50+
class Uint256:
51+
@classmethod
52+
def decode(cls, reader: io.IOBase) -> int:
53+
return int.from_bytes(pleth.io.read_full(reader, 32), 'big')
54+
55+
@classmethod
56+
def encode(cls, origin: int) -> bytearray:
57+
assert origin >= 0
58+
assert origin <= 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
59+
return bytearray(origin.to_bytes(32, 'big'))

pleth/io.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import io
2+
3+
4+
def read_full(reader: io.IOBase, n: int) -> bytearray:
5+
# Read exactly n bytes from reader, or raise EOFError.
6+
data = bytearray()
7+
while len(data) < n:
8+
once = reader.read(n - len(data))
9+
if not once:
10+
raise EOFError('io: EOF')
11+
data.extend(once)
12+
return data

0 commit comments

Comments
 (0)