Added a few utility files

This commit is contained in:
Vitalik Buterin 2017-05-19 00:15:23 -04:00
parent 2cd5415396
commit 318bf043ed
5 changed files with 91 additions and 7 deletions

39
forwarder.py Normal file
View File

@ -0,0 +1,39 @@
from ethereum import utils
def mk_forwarder(address):
code = b'\x36\x60\x00\x60\x00\x37' # CALLDATACOPY 0 0 (CALLDATASIZE)
code += b'\x61\x20\x00\x60\x00\x36\x60\x00' # 8192 0 CALLDATASIZE 0
code += b'\x73' + utils.normalize_address(address) + b'\x5a' # address gas
code += b'\xf4' # delegatecall
code += b'\x61\x20\x00\x60\x00\xf3' # 8192 0 RETURN
return code
def mk_wrapper(code):
lencodepush = b'\x60' + utils.encode_int(len(code)) # length of code
returner = lencodepush + b'\x60\x0c\x60\x00' # start from 12 in code, 0 in memory
returner += b'\x39' # CODECOPY
returner += lencodepush + b'\x60\x00' + b'\xf3' # return code
assert len(returner) == 12
return returner + code
kode = """
moose: num
def increment_moose(i: num) -> num:
self.moose += i
return self.moose
"""
def test():
from ethereum.tools import tester2
c = tester2.Chain()
x = c.contract(kode, language='viper')
fwdcode = mk_forwarder(x.address)
initcode = mk_wrapper(fwdcode)
y = c.contract(initcode, language='evm')
assert c.head_state.get_code(y) == fwdcode
z = tester2.ABIContract(c, x.translator, y)
assert z.increment_moose(3) == 3
assert z.increment_moose(5) == 8
if __name__ == '__main__':
test()

23
mk_sendmany.py Normal file
View File

@ -0,0 +1,23 @@
from ethereum import utils
def mk_multisend_code(payments): # expects a dictionary, {address: wei}
kode = b''
for address, wei in payments.items():
kode += b'\x60\x00\x60\x00\x60\x00\x60\x00' # 0 0 0 0
encoded_wei = utils.encode_int(wei) or b'\x00'
kode += utils.ascii_chr(0x5f + len(encoded_wei)) + encoded_wei # value
kode += b'\x73' + utils.normalize_address(address) # to
kode += b'\x60\x00\xf1\x50' # 0 CALL POP
kode += b'\x33\xff' # CALLER SELFDESTRUCT
return kode
def get_multisend_gas(payments):
o = 26002 # 21000 + 2 (CALLER) + 5000 (SELFDESTRUCT)
for address, wei in payments.items():
encoded_wei = utils.encode_int(wei) or b'\x00'
# 20 bytes in txdata for address = 1360
# bytes in txdata for wei = 68 * n
# gas for pushes and pops = 3 * 7 + 2 = 23
# CALL = 9700 + 25000 (possible if new account)
o += 1360 + 68 * len(encoded_wei) + 23 + 34700
return o

14
sendmany_tester.py Normal file
View File

@ -0,0 +1,14 @@
from mk_sendmany import mk_multisend_code, get_multisend_gas
from ethereum.tools import tester2
from ethereum import utils
# from ethereum.slogging import get_logger, configure_logging
# logger = get_logger()
# configure_logging(':trace')
c = tester2.Chain()
args = {utils.int_to_addr(10000 + i ** 3): i ** 3 for i in range(1, 101)}
c.tx(to=b'', value=sum(args.values()), data=mk_multisend_code(args), startgas=get_multisend_gas(args), gasprice=20 * 10**9)
for addr, value in args.items():
assert c.head_state.get_balance(addr) == value
print("Test successful")

View File

@ -24,7 +24,7 @@ G2 = (FQ2([108570469990230571359445707622328294813707563595785180869905199932856
# Check that a point is on the curve defined by y**2 == x**3 + b
def is_on_curve(pt, b):
if pt is None:
if pt[-1] == pt[-1].__class__.zero():
return True
x, y, z = pt
return y**2 * z - x**3 == b * z**3
@ -49,7 +49,7 @@ def double(pt):
def add(p1, p2):
one, zero = p1[0].__class__.one(), p1[0].__class__.zero()
if p1[2] == zero or p2[2] == zero:
return p1 if zero else p2
return p1 if p2[2] == zero else p2
x1, y1, z1 = p1
x2, y2, z2 = p2
U1 = y2 * z1
@ -75,7 +75,7 @@ def add(p1, p2):
# Elliptic curve point multiplication
def multiply(pt, n):
if n == 0:
return None
return (pt[0].__class__.one(), pt[0].__class__.one(), pt[0].__class__.zero())
elif n == 1:
return pt
elif not n % 2:

View File

@ -64,7 +64,7 @@ assert linefunc(one, one, two)[0] != FQ(0)
assert linefunc(one, one, negtwo)[0] == FQ(0)
# Main miller loop
def miller_loop(Q, P):
def miller_loop(Q, P, final_exponentiate=True):
if Q is None or P is None:
return FQ12.one()
R = Q
@ -97,10 +97,18 @@ def miller_loop(Q, P):
_n2, _d2 = linefunc(R, nQ2, P)
f = f_num * _n1 * _n2 / (f_den * _d1 * _d2)
# R = add(R, nQ2) This line is in many specifications but it technically does nothing
return f ** ((field_modulus ** 12 - 1) // curve_order)
if final_exponentiate:
return f ** ((field_modulus ** 12 - 1) // curve_order)
else:
return f
# Pairing computation
def pairing(Q, P):
def pairing(Q, P, final_exponentiate=True):
assert is_on_curve(Q, b2)
assert is_on_curve(P, b)
return miller_loop(twist(Q), cast_point_to_fq12(P))
if P[-1] == P[-1].__class__.zero() or Q[-1] == Q[-1].__class__.zero():
return FQ12.one()
return miller_loop(twist(Q), cast_point_to_fq12(P), final_exponentiate=final_exponentiate)
def final_exponentiate(p):
return p ** ((field_modulus ** 12 - 1) // curve_order)