The issue here is that your variable has a fixed length of 32 bytes, which explains the zeroes in the right. You can strip the zeros in python:
zbytes32 = contractInstance.functions.getzBytes32().call()
zbytes32 = zbytes32.hex().rstrip("0")
if len(zbytes32) % 2 != 0:
zbytes32 = zbytes32 + '0'
zbytes32 = bytes.fromhex(zbytes32).decode('utf8')
Printing the variable zbytes32 gives: 'HelloBytes32' and:
zbytes32=='HelloBytes32'
is True
The conditional part if len(zbytes32) % 2 != 0
is there because it may be that the last character is indeed zero and we are removing it, the way to know this is that every byte is represented by two hexadecimal characters so if the length of the variable zbytes32 after removing the zeros is odd, one zero must be added to the right.
Hope this helps
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
)
Best Answer
Simply
data.encode('utf-8')
should be sufficient, if you are converting a string to bytes data.If your string is more than 32 bytes long after encoding to UTF-8, then your problem is that your contract can't accept the data you want to send.
More background
If a function takes a
bytes32
, it cannot accept a value longer than 32 bytes. Web3.py will actually reject the function as a possibility based on the type mismatch (because multiple functions with the same name and different types are allowed).If you have more than 32 bytes to send in, you probably don't want to blindly clip off the end. What you need to do will be highly dependent on the semantics of the contract that you are interacting with.
You do not need to pad the value, Web3.py will handle that for you.
Finally,
bytes(str_data, 'utf-8')
is equivalent tostr_data.encode('utf-8')
. Which you prefer is a matter of taste, I suppose, and potentially performance.