[Ethereum] How to send a python bytearray into solidity function by web3.py

pythontransactionsweb3.py

I have a solidity function declared as:

function setUnitData(bytes32[10] my_input_array) public payable {...}

When I run this code:

contract = self.contract_instance['../contracts/test.sol:test']

test_byte = b'0x01234567890123456789012345678901' * 24
tx_hash = contract.functions.setUnitData(test_byte).transact({'from': self.w3.toChecksumAddress(unit['update_account']), 'gas': 3400000})

I get this ValidationError:

web3.exceptions.ValidationError:
Could not identify the intended function with name setUnitData, positional argument(s) of type (<class 'bytes'>,) and keyword argument(s) of type {}.
Found 1 function(s) with the name setUnitData: ['setUnitData(bytes32[10])']
Function invocation failed due to no matching argument types.

Any possible or best way to send the python byte array or any workable type to this function?

Best Answer

The function setUnitData(bytes32[10]) requires an array of 10 elements, each of which is 32 bytes of data. Since we don't know the purpose of the function, let's generate a some random data of that type:

>>> input_array = [bytes(range(idx, 32 + idx)) for idx in range(10)]
[b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f',
 b'\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ',
 b'\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !',
 b'\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"',
 b'\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#',
 b'\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$',
 b'\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%',
 b'\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&',
 b'\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'',
 b'\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'(']

If looking at native bytes values in python makes you grumpy, you can convert to hex strings. Web3.py will accept either.

>>> from web3 import Web3
>>> hex_array = [Web3.toHex(bytes_data) for bytes_data in input_array] 
['0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
 '0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20',
 '0x02030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021',
 '0x030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122',
 '0x0405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223',
 '0x05060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324',
 '0x060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425',
 '0x0708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526',
 '0x08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627',
 '0x090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728']

Now you can send a transaction with:

contract = self.contract_instance['../contracts/test.sol:test']
tx_hash = contract.functions.setUnitData(input_array).transact({'from': self.w3.toChecksumAddress(unit['update_account']), 'gas': 3400000})

(hex_array also works, in place of input_array)