Me gustaría convertir bytes en cualquier otro tipo. Es decir, "0x57D80C61128d608857d5310BB514223Bb6011CAB"
en la dirección 0x57D80C61128d608857d5310BB514223Bb6011CAB
, "5"
en el uint256 5
y así sucesivamente. He seguido todos los fragmentos que pude encontrar, pero no puedo hacer que ninguno funcione después de la versión 0.5.0. Creo que el culpable es el cambio descrito aquí:
Las conversiones entre
bytesX
yuintY
de diferente tamaño ahora no están permitidas debido albytesX
relleno a la derecha yuintY
al relleno a la izquierda, lo que puede causar resultados de conversión inesperados. El tamaño ahora debe ajustarse dentro del tipo antes de la conversión. Por ejemplo, puede convertirbytes4
(4 bytes) enuint64
(8 bytes) convirtiendo primero labytes4
variable enbytes8
y luego enuint64
. Obtiene el relleno opuesto al convertir a través deuint32
.
Tomando el ejemplo de uint, aquí hay un código que habría funcionado antes de esta versión del compilador:
function bytesToUInt(string memory _b) public returns (uint256){
bytes memory b = bytes(_b);
uint256 number;
for(uint i=0;i<b.length;i++){
number = number + uint(b[i])*(2**(8*(b.length-(i+1))));
}
return number;
}
Pero esto ahora da como resultado un TypeError: Explicit type conversion not allowed
, he intentado mover las cosas y agregar conversiones adicionales, pero nada ha funcionado.
Para bytes
, address
he intentado esto:
function bytesToAddress(string memory _b) public returns (address) {
bytes20 b = bytes20(bytes(_b));
return address(uint160(b));
}
Pero no puedes convertir explícitamente de bytes memory
a bytes20
y tampoco pude hacerlo funcionar.
¿Puede alguien mostrarme cómo se hace esto correctamente? Gracias.
Hasta donde yo sé, necesitará ensamblaje en línea. Alguien ya publicó algún código aplicable a las versiones anteriores de solidity al menos, aunque, en general, el ensamblaje en línea corto y correcto debería ser bastante universal.
Aquí hay un código que convierte algunos bytes de la memoria a bytes20 (solo los primeros 20, se trunca si supera eso, por supuesto).
contract t {
function tb20(bytes memory _b)
public
pure
returns (bytes20 _result) {
assembly {
_result := mload(add(_b, 0x20))
}
}
function bytesToAddress(bytes memory _b)
public
returns (address) {
return address(tb20(_b));
}
}
No hay garantías ni garantías sobre el código, pero parece funcionar. Por supuesto, puede cambiar tb20 para devolver una dirección en su lugar, aunque entonces necesitará turnos.
Mi respuesta anterior tiene que ver con convertir un tipo de bytes de la memoria en bytes20, porque así es como entendí la pregunta del título, convirtiendo bytes dinámicos, a bytes de tamaño estático 1-32, y luego en cualquier otro derivado.
Con respecto a la pregunta real en su cuerpo, esta respuesta es para confirmar que, de hecho, puede usar su bytesToUInt
función existente para solc 0.5.x. Aún puede realizar conversiones explícitas entre otros bytes estáticos, siempre que sus longitudes correspondientes sean iguales. Por lo tanto, si tiene algo bytes32 y desea que sea uint128, primero debe convertirlo explícitamente a bytes16 y luego puede convertirlo a uint128, a través de solidez regular. Por supuesto, querrá depurar/probar para ver qué partes de esos bytes32 pueden truncarse antes de continuar con esto, ya que hay casos opuestos en los que puede tener más sentido convertirlo a uint256 primero y luego reducirlo a uint128. .
Simplemente dicho, puede hacer que su función existente funcione, convirtiendo el bytes1
a uint8
primero.
function bytesToUInt(string memory _b) public returns (uint256){
bytes memory b = bytes(_b);
uint256 number;
for(uint i=0;i<b.length;i++){
number = number + uint256(uint8(b[i]))*(2**(8*(b.length-(i+1))));
}
return number;
}
el uint256 se agregó para mayor claridad, lo que probablemente siempre sea una buena idea, pero no es necesario
bytesToAddress
se convertirá de una secuencia de bytes a uint256, si la cadena tiene dígitos hexadecimales, primero debe convertirlos a su valor. Algo como esto ethereum.stackexchange.com/a/40247/2124 primero.El error que estaba cometiendo provino de la conversión inicial a bytes. Debido a que puede pasarles cualquier cosa con bytes()
, asumí que esto me estaba dando algo que podía pasar a las otras funciones, no fue así.
Mi problema no fue con 0.5.x en absoluto, si convierte a bytes correctamente, el resto del código funciona como se esperaba. Solo tiene un par de conversiones adicionales que hacer en comparación con 0.4.x. La biblioteca Seriality funciona muy bien.
Aquí hay un ejemplo de una conversión de un int a bytes y de regreso a ese int:
function intToBytesToInt(int256 _input) public pure returns (int256) {
bytes memory buffer = new bytes(32);
uint offset = 32;
assembly{
mstore(add(buffer, offset), _input)
}
//b is the converted input
bytes memory b = buffer;
//Post 0.5.0 you must remember to convert to the appropriate size. For int256, that's bytes32.
bytes32 preI;
assembly {
preI := mload(add(buffer, offset))
}
//i is b converted back to an int256
int256 i = int256(preI);
return i;
}
mikko ohtamaa
FlashyQpt