test_basic.py (7385B)
1 # standard imports 2 import unittest 3 import logging 4 import os 5 6 # external imports 7 from chainlib.eth.contract import ABIContractType 8 from chainlib.eth.tx import TxFactory 9 from chainlib.eth.tx import TxFormat 10 from chainlib.jsonrpc import JSONRPCRequest 11 from chainlib.eth.contract import ABIContractEncoder 12 from chainlib.eth.contract import ABIContractType 13 from hexathon import add_0x 14 from hexathon import strip_0x 15 16 # local imports 17 from eth_erc712.unittest import TestERC712 as TestERC712Base 18 from eth_erc712 import ERC712Encoder 19 from eth_erc712 import EIP712DomainEncoder 20 21 logging.basicConfig(level=logging.DEBUG) 22 logg = logging.getLogger() 23 24 25 class ExamplePerson(ERC712Encoder): 26 27 def __init__(self, name, wallet): 28 super(ExamplePerson, self).__init__('Person') 29 self.add('name', ABIContractType.STRING, name) 30 self.add('wallet', ABIContractType.ADDRESS, wallet) 31 32 33 class ExampleMail(EIP712DomainEncoder): 34 def __init__(self, from_name, from_wallet, to_name, to_wallet, contents, domain): 35 self.pfrom = ExamplePerson(from_name, from_wallet) 36 self.pto = ExamplePerson(to_name, to_wallet) 37 super(ExampleMail, self).__init__('Mail', domain) 38 self.typ_literal('Person from') 39 self.typ_literal('Person to') 40 self.add('contents', ABIContractType.STRING, contents) 41 42 43 # In general implementation, remember to sort structs alphabetically 44 def get_method(self): 45 typ = super(ExampleMail, self).get_method() 46 typ += self.pto.get_method() 47 logg.debug('Method is composite type: ' + typ) 48 return typ 49 50 51 def encode_data(self): 52 content = super(ExampleMail, self).encode_data() 53 from_content = self.pfrom.encode_data() 54 to_content = self.pto.encode_data() 55 return from_content + to_content + content 56 57 58 class TestERC712(TestERC712Base): 59 60 def test_domain_separator(self): 61 r = self.domain.encode_type() 62 self.assertEqual(r, bytes.fromhex('d87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472')) 63 64 65 def test_domain_data(self): 66 r = self.domain.get() 67 print(r.hex()) 68 69 70 def test_mail_manual(self): 71 a = os.urandom(20) 72 b = os.urandom(20) 73 mail_from_name = 'Pinky Inky' 74 mail_from_address = a.hex() 75 mail_to_name = 'Clyde Blinky' 76 mail_to_address = b.hex() 77 mail_contents = 'barbarbar' 78 79 mail = ExampleMail( 80 mail_from_name, 81 mail_from_address, 82 mail_to_name, 83 mail_to_address, 84 mail_contents, 85 self.domain, 86 ) 87 sig = self.signer.sign_typed_message(self.accounts[0], mail.get_domain(), mail.get_hash()) 88 sig = sig[:64] + (sig[64] + 27).to_bytes(1, byteorder='big') 89 logg.debug('message is:\n{}\nsigned by {}'.format(mail, self.accounts[0])) 90 91 logg.debug('encode data from') 92 enc = ABIContractEncoder() 93 enc.string(mail_from_name) 94 enc.address(mail_from_address) 95 data_from = enc.get_contents() 96 97 logg.debug('encode data to') 98 enc = ABIContractEncoder() 99 enc.string(mail_to_name) 100 enc.address(mail_to_address) 101 data_to = enc.get_contents() 102 103 logg.debug('encode data contents') 104 enc = ABIContractEncoder() 105 enc.string(mail_contents) 106 data_contents = enc.get_contents() 107 108 logg.debug('encode struct data pointers') 109 enc = ABIContractEncoder() 110 enc.uint256(0x60) 111 enc.uint256(0xe0) 112 enc.uint256(0x160) 113 struct_pointers = enc.get_contents() 114 115 logg.debug('encode complete calldata') 116 c = TxFactory(self.chain_spec) 117 j = JSONRPCRequest() 118 o = j.template() 119 o['method'] = 'eth_call' 120 enc = ABIContractEncoder() 121 enc.method('verify') 122 enc.typ_literal('((string,address),(string,address),string)') 123 enc.typ(ABIContractType.UINT8) 124 enc.typ(ABIContractType.BYTES32) 125 enc.typ(ABIContractType.BYTES32) 126 enc.uint256(0x80) # start of struct data pointer 127 enc.uintn(sig[64], 8) 128 enc.bytes32(sig[:32]) 129 enc.bytes32(sig[32:64]) 130 data = enc.get() 131 data += struct_pointers 132 data += data_from 133 data += data_to 134 data += data_contents 135 for i in range(8, len(data), 64): 136 logg.info('calldata {} {}'.format((i-8).to_bytes(2, byteorder='big').hex(), data[i:i+64])) 137 data = add_0x(data) 138 tx = c.template(self.accounts[0], self.address) 139 tx = c.set_code(tx, data) 140 o['params'].append(c.normalize(tx)) 141 o['params'].append('latest') 142 o = j.finalize(o) 143 r = self.rpc.do(o) 144 r = strip_0x(r) 145 self.assertEqual(int(r, 16), 1) 146 147 148 def test_mail_chainlib_abi(self): 149 a = os.urandom(20) 150 b = os.urandom(20) 151 mail_from_name = 'Pinky Inky' 152 mail_from_address = a.hex() 153 mail_to_name = 'Clyde Blinky' 154 mail_to_address = b.hex() 155 mail_contents = 'barbarbar' 156 157 mail = ExampleMail( 158 mail_from_name, 159 mail_from_address, 160 mail_to_name, 161 mail_to_address, 162 mail_contents, 163 self.domain, 164 ) 165 sig = self.signer.sign_typed_message(self.accounts[0], mail.get_domain(), mail.get_hash()) 166 sig = sig[:64] + (sig[64] + 27).to_bytes(1, byteorder='big') 167 logg.debug('message is:\n{}\nsigned by {}'.format(mail, self.accounts[0])) 168 169 logg.debug('encode data from') 170 enc_from = ABIContractEncoder() 171 enc_from.typ(ABIContractType.STRING) 172 enc_from.typ(ABIContractType.ADDRESS) 173 enc_from.string(mail_from_name) 174 enc_from.address(mail_from_address) 175 176 logg.debug('encode data to') 177 enc_to = ABIContractEncoder() 178 enc_to.typ(ABIContractType.STRING) 179 enc_to.typ(ABIContractType.ADDRESS) 180 enc_to.string(mail_to_name) 181 enc_to.address(mail_to_address) 182 183 logg.debug('encode data contents') 184 enc_mail = ABIContractEncoder() 185 enc_mail.typ(enc_from) 186 enc_mail.typ(enc_to) 187 enc_mail.typ(ABIContractType.STRING) 188 enc_mail.tuple(enc_from) 189 enc_mail.tuple(enc_to) 190 enc_mail.string(mail_contents) 191 192 logg.debug('encode complete calldata') 193 c = TxFactory(self.chain_spec) 194 j = JSONRPCRequest() 195 o = j.template() 196 o['method'] = 'eth_call' 197 enc = ABIContractEncoder() 198 enc.method('verify') 199 enc.typ(enc_mail) 200 enc.typ(ABIContractType.UINT8) 201 enc.typ(ABIContractType.BYTES32) 202 enc.typ(ABIContractType.BYTES32) 203 enc.tuple(enc_mail) 204 enc.uintn(sig[64], 8) 205 enc.bytes32(sig[:32]) 206 enc.bytes32(sig[32:64]) 207 data = enc.get() 208 for i in range(8, len(data), 64): 209 logg.info('calldata {} {}'.format((i-8).to_bytes(2, byteorder='big').hex(), data[i:i+64])) 210 data = add_0x(data) 211 tx = c.template(self.accounts[0], self.address) 212 tx = c.set_code(tx, data) 213 o['params'].append(c.normalize(tx)) 214 o['params'].append('latest') 215 o = j.finalize(o) 216 r = self.rpc.do(o) 217 r = strip_0x(r) 218 self.assertEqual(int(r, 16), 1) 219 220 221 if __name__ == '__main__': 222 unittest.main()