¿Cómo podría convertir el tipo de uint al tipo de bytes en solidez?

Quiero convertir datos de tipo uint a tipo de bytes en solidez. He encontrado una respuesta sobre esto que es como a continuación.

function toBytes(uint256 x) public pure returns (bytes memory b) {
    b = new bytes(32);
    assembly { mstore(add(b, 32), x) }
}

Pero esto no funciona como pensaba. Por ejemplo, si pongo 0x0000000000000000000000000000000000000000000000000000000000000abcel valor de entrada, esperaba tener un valor de retorno que se vea así 0xabc0000000000000000000000000000000000000000000000000000000000000. Pero esta función devuelve lo mismo que el valor de entrada, que es 0x0000000000000000000000000000000000000000000000000000000000000abc. ¿Cómo podría convertir 0x0000000000000000000000000000000000000000000000000000000000000abcesto en 0xabc0000000000000000000000000000000000000000000000000000000000000esto en solidez?

¿Podría elaborar un poco más sobre qué es exactamente lo que está tratando de lograr? En su ejemplo, los límites de bytes no se conservan. El original uinttiene bytes 0ay bc, mientras que el resultante bytestiene aby c0.
@MikhailVladimirov Quise decir que si pongo el valor de entrada uint256 0x0000000000000000000000000000000000000000000000000000000000000abcen una función, quiero recibir 0xabc.
0xabcno es un bytesvalor válido, ya que tiene una longitud de 12 bits, mientras que cada byte tiene 8 bits. Entonces es un número fraccionario de bytes.
@MikhailVladimirov Oh, está bien, entonces cambiaré mi ejemplo a 0x000000000000000000000000000000000000000000000000000000000000abcd. Quiero recibir 0xabcdcuando doy un valor de entrada 0x000000000000000000000000000000000000000000000000000000000000abcd. Pero esa función devuelve lo mismo que el valor de entrada.
Pero, ¿cuál sería la salida correcta para el ejemplo original? Necesito esto para entender la regla general.
¿Quizás quiera convertir de Little Endian a Big Endian?

Respuestas (2)

Lo que está buscando hacer se llama cambio de bits . Solidity permite el cambio de bit usando los operadores <<y >>.

Para su ejemplo, la parte distinta de cero 0x000000000000000000000000000000000000000000000000000000000000abcdes abcdla que ocupa 16 bits. Debido a que un bytes32 tiene una longitud de 256 bits, debe cambiar 240 bits para devolver el valor deseado:

function toBytes(uint256 x) public pure returns (bytes32) {
    return bytes32(a) << 240;
}

Tenga en cuenta que el ejemplo anterior solo funciona cuando el valor inicial es de 2 bytes. Si no está seguro de la longitud de su valor inicial, puede determinarlo usando un ciclo for y alguna división:

function toBytes(uint256 a) public pure returns (bytes32) {
    uint i;
    for (i = 0; i < 33; i++) {
        if (a / 256**i == 0) break;
    }
    return bytes32(a) << (32-i)*8;
}

Otras lecturas:

OP quiere convertir a bytesno a bytes32.

¿Qué pasa con esto?

function toBytes(uint256 x) public pure returns (bytes memory b) {
  uint l = 32;

  if (x < 0x100000000000000000000000000000000) { x <<= 128; l -= 16; }
  if (x < 0x1000000000000000000000000000000000000000000000000) { x <<= 64; l -= 8; }
  if (x < 0x100000000000000000000000000000000000000000000000000000000) { x <<= 32; l -= 4; }
  if (x < 0x1000000000000000000000000000000000000000000000000000000000000) { x <<= 16; l -= 2; }
  if (x < 0x100000000000000000000000000000000000000000000000000000000000000) { x <<= 8; l -= 1; }
  if (x < 0x100000000000000000000000000000000000000000000000000000000000000) { x <<= 8; l -= 1; }

  b = new bytes (l);

  assembly { mstore(add(b, 32), x) }
}

Para mí lo hace:

0x0 -> 0x        (zero bytes)
0x1 -> 0x01      (1 byte)
0xFF -> 0xFF     (1 byte)
0x100 -> 0x0100  (2 bytes)
0xFFFF -> 0xFFFF (2 bytes)
etc.