Cómo convertir/decodificar Solidity bytes32 a una cadena de Python a través de web3.py

Dentro de un contrato de Solidity, tengo esta variable: zBytes32 = "HelloBytes32";

después de que Python web3.py recupere esa variable,

zbytes32 = contractInstance.functions.getzBytes32().call()

print(zbytes32) muestra cuál es el valor de zbytes32:

# b'HelloBytes32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

zbytes32 = zBytes32.decode('utf8')# shows HelloBytes32
print(zbytes32) 

decode('utf8') elimina b en el frente, print() ocultará TODOS los \x00, ¡pero TODAVÍA ESTÁN AQUÍ! Probarlo:

zBytes32str= str(zbytes32)
print('zbytes32 = '+ zBytes32str)
if zBytes32str == 'HelloBytes32':
    print('zbytes32str == "HelloBytes32"')
else:
    print('zbytes32str != "HelloBytes32"')

zbytes32str != ¡¡¡Se muestra "HelloBytes32"!!! ENTONCES, ¿CÓMO PUEDO decodificar correctamente byte32 en Python?

print('\ngetBytes32 raw: {}'.format(zbytes32))# shows HelloBytes32
print('zbytes32.decode("utf8") as string = '+ zbytes32)# shows HelloBytes32

AUNQUE se ven iguales a HelloBytes32, ¡en realidad NO lo son!

Tal vez eso explique la siguiente situación:

arr = contractInstance.functions.getVariables().call()
print('arr[4] in str()= '+ str(arr[4]))#must be converted to string
b2= arr[4].decode('utf8')
print('b2.decode("utf8")= '+ b2)
arr[4] = ''
print('after arr[4] = "", arr[4]= '+ arr[4])
arr[4] = b2
print('after arr[4] = b2, arr[4]= '+ arr[4])
arr[0] = 'What man?'
print('after arr[0] = "What man?", arr[0]= '+ arr[0])
print('\nget many variables: {}'.format(arr))

se muestra en la terminal:

arr[4] in str()= b'HelloBytes32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
b2.decode("utf8")= HelloBytes32
after arr[4] = "", arr[4]= 
after arr[4] = b2, arr[4]= HelloBytes32
after arr[0] = "What man?", arr[0]= What man?

get many variables: ['What man?', '0x583031D11...', 111111, False, 'HelloBytes32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ['0xCA35b7d...', '0x14723A...'], [9999999, 555555]]

Vea la matriz anterior. Cuando configuro un nuevo valor para arr[0], funciona.

Pero cuando configuro un nuevo valor para arr[4], funciona...

¿POR QUÉ cuando muestro toda la matriz, arr[4] todavía muestra esos \x00 ???

Necesito pasar esos valores a otro script, así que debo asegurarme de que estén limpios de esos \x00. Por favor ayuda. Gracias

Respuestas (3)

El problema aquí es que su variable tiene una longitud fija de 32 bytes, lo que explica los ceros a la derecha. Puedes quitar los ceros en 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')

Imprimir la variable zbytes32 da: 'HelloBytes32' y: zbytes32=='HelloBytes32'esTrue

La parte condicional if len(zbytes32) % 2 != 0está ahí porque puede ser que el último carácter sea cero y lo estemos eliminando, la forma de saber esto es que cada byte está representado por dos caracteres hexadecimales, por lo que si la longitud de la variable zbytes32 después de eliminar los ceros es impar, se debe agregar un cero a la derecha.

Espero que esto ayude

¡GRACIAS Jaime! También hice esta respuesta: Cómo convertir/codificar cadenas a bytes32 en Python para argumentos de Solidity bytes32 a través de web3.py ethereum.stackexchange.com/questions/30683/…

Dado que parece estar asumiendo que los bytes son decodificables con UTF-8, es posible que desee un stringtipo en Solidity en lugar de bytes32.

Si cambia el tipo de variable a Cadena y vuelve a implementar, el contrato web3.py con la nueva ABI le devolverá una cadena ya decodificada como "HelloBytes32".

Gracias tallador. Es bueno señalar que asumí que es decodificable con UTF-8. Debería ser consciente de eso. Gracias
from web3 import Web3
string_content = Web3.toText(bytes_content)