¿Convertir de bytes en 0.5.x?

Me gustaría convertir bytes en cualquier otro tipo. Es decir, "0x57D80C61128d608857d5310BB514223Bb6011CAB"en la dirección 0x57D80C61128d608857d5310BB514223Bb6011CAB, "5"en el uint256 5y 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 bytesXy uintYde diferente tamaño ahora no están permitidas debido al bytesXrelleno a la derecha y uintYal 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 convertir bytes4(4 bytes) en uint64(8 bytes) convirtiendo primero la bytes4variable en bytes8y luego en uint64. Obtiene el relleno opuesto al convertir a través de uint32.

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, addresshe 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 memorya bytes20y tampoco pude hacerlo funcionar.

¿Puede alguien mostrarme cómo se hace esto correctamente? Gracias.

Mira esto: github.com/pouladzade/Seriality - no estoy seguro si funciona en 0.5.0 pero la biblioteca proporciona una forma eficiente de convertir tipos de datos a través de asm en línea
@MikkoOhtamaa Desafortunadamente, el ensamblaje está desactualizado para 0.5.x: solidity.readthedocs.io/en/v0.5.2/assembly.html

Respuestas (3)

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.

Esto tampoco funciona para mí, obtengo una dirección de aspecto normal, pero no es la que uso como entrada. Para ser claros, estoy ejecutando esto en remix con la versión de solidez 0.5.2. ¿Quizás es un problema con el remix?
No es un problema de remezcla: rinkeby.etherscan.io/address/…

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 bytesToUIntfunció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 bytes1a uint8primero.

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

Convertir bytes1 a uint8 también fue mi primer pensamiento, pero no. "5" devuelve 53, "0" devuelve 48, "124" devuelve 3224068, etc. Está fuera de 48 de 0 a 9 y luego se vuelve más complejo. Pensé que podría ser la conversión de cadena a bytes, pero aparentemente no.
Pero publicaste esa función, y el resultado que produce la función anterior que publiqué para solc 0.5 es el mismo que publicaste y dijiste que estaba funcionando. Mis respuestas responden a sus preguntas, pero no creo que haya hecho las preguntas correctas para lo que realmente está buscando. Creo que es posible que desee volver a publicar una nueva pregunta adecuada. Creo que lo que de hecho está buscando es un convertidor de cadena base 10 en uint, que existe. Consulte la API de Oraclize para ver algunos ayudantes que funcionan.
@FlashyQpt La función bytesToAddressse 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.
Pensé que funcionaría en 0.4.x, tontamente no me molesté en probar esto. Interpreté mal lo que se suponía que era la entrada. @Ismael Gracias, creo que solucionaste mi problema

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;
}