Compara los últimos 2 dígitos del hash de bloque

Tengo problemas para hacer una comparación de cadenas con los últimos 2 dígitos de un hash de bloque en Solidity. También estoy un poco confundido acerca de cómo trabajar con un solo carácter, ya que parece que un solo byte en Solidity contiene 2 caracteres.

Tomo un blockhash:

bytes32 myHash = block.blockhash(block.number - 1);

Y obtengo algo como:

"0x18676e992055c057538d59b378271bb4eacdb7f6abf9e815fd63255dc11166b6"

Intento agarrar el último carácter haciendo:

byte x = myHash[31];

Esto me da un valor como este, cuando se imprime en un registro:

"b60000000000000000000000000000000000000000000000000000000000000000"

Aquí es donde estoy confundido. Estos son los últimos 2 caracteres de los bytes32. Quiero usar la siguiente función para determinar el valor entero hexadecimal del carácter:

function getCoordinate(byte val) returns(uint) {
    if (val == "0") {
        return 0;
    } else if (val == "1") {
        return 1;
    } else if (val == "2") {
        return 2;
    } else if (val == "3") {
        return 3;
    } else if (val == "4") {
        return 4;
    } else if (val == "5") {
        return 5;
    } else if (val == "6") {
        return 6;
    } else if (val == "7") {
        return 7;
    } else if (val == "8") {
        return 8;
    } else if (val == "9") {
        return 9;
    } else if (val == "a") {
        return 10;
    } else if (val == "b") {
        return 11;
    } else if (val == "c") {
        return 12;
    } else if (val == "d") {
        return 13;
    } else if (val == "e") {
        return 14;
    } else if (val == "f") {
        return 15;
    }
}

Sin embargo, ninguno de los casos coincide, por lo que siempre devuelve 0. ¿Alguien sabe cómo obtener un solo carácter para que esta función funcione correctamente?

¿Qué quiere decir con valor entero hexadecimal? ¿Está diciendo que desea convertir el último byte del hash a su valor entero?
Sí, exactamente, lo expresé mal. Quiero pasar del caracter hexadecimal en los bytes32 a un valor entero (entre 1 y 16)

Respuestas (3)

Dado que cada byte está codificado como 2 caracteres hexadecimales (por ejemplo, en su ejemplo, el último byte es 0xb6), necesita 2 funciones: una para la coordenada izquierda, otra para la coordenada derecha:

function getRightCoordinate(byte input) returns(uint) {
    byte val = input & byte(15);
    return uint(val);
}

function getLeftCoordinate(byte input) returns(uint) {
    byte val = input >> 4;
    return uint(val);
}

15es la representación decimal del binario 00001111. Bitwise &te da la coordenada correcta.

>> 4desplaza los primeros 4 bits a la derecha descartando los otros 4 bits.

Gracias, esto es exactamente lo que estaba buscando, y es más eficiente que la respuesta que publiqué. Aceptando esta respuesta.

Los bytes tienen 8 bits, por lo que un solo byte contendrá hasta 256 (2*2*2*2*2*2*2*2) valores. Un carácter hexadecimal tiene 16 valores (10 dígitos + 6 letras), por lo que utiliza 2 caracteres hexadecimales cuando representa un byte (16*16 = 256).

bytes32los tipos de datos se pueden convertir sin problemas en un número de tipo uint256(32 bytes de 8 bits hacen 256 bits), por lo que lo más obvio es convertir el hash del bloque en un número, dividirlo por 16 y tomar el resto. El siguiente código (no probado) debería darte un número del 0 al 15:

uint256 your_num = uint256(block.blockhash(block.number - 1)) % 16;

¡Impresionante! Voy a probar esto tan pronto como esté de vuelta en mi computadora. Seguirá aquí después.
Supongo que leí mal esto antes porque esto no funcionará para mí. Necesito obtener un número entero 1-16 específicamente del último dígito del blockhash. No puedo usar todos los personajes. La razón es que tendré que hacer esto también para otro personaje. por ejemplo, los últimos caracteres son "0a", luego los 2 números son 0 y 10.

Pude usar la sugerencia de Edmund de trabajar con uint256 para encontrar una solución a mi problema. Mediante un cambio de bits creativo, puede obtener el valor entero de un solo dígito. En mi caso, quería los últimos 2 dígitos del blockhash.

bytes32 myHash = block.blockhash(block.number - 1);
uint256 hashNum = uint256(myHash);

// Last Character alone
// Shift left by 252 bits (leaving just 4 bits left), then shift back to the right
uint256 last = (hashNum * 2 ** 252) / (2 ** 252);

// Second to last character alone
// Shift left by 248 bits (leaving 8 bits left), but then shift right by 252
uint256 secondLast = (hashNum * 2 ** 248) / (2 ** 252);

Así que ahí lo tienes, los últimos 2 caracteres del blockhash como números enteros entre 0 y 15.

Existe una solución más óptima que utiliza enmascaramiento de bits en lugar de desplazamiento. Lo publicaré aquí más tarde si consigo que funcione.