¿Cómo se calcula la sección de destino de un encabezado de bloque?

Estuve hurgando en https://en.bitcoin.it/wiki/Target y encontré el objetivo actual, pero parece que no puedo encontrar cómo se genera. Supuestamente se genera cuando se ajusta la dificultad, como se indica aquí: https://en.bitcoin.it/wiki/Block_hashing_algorithm , pero ¿cuál es exactamente el algoritmo para generar el objetivo? Si alguien pudiera mostrarme algún psuedocódigo, sería genial.

No me queda claro si está buscando una explicación verbal del algoritmo de dificultad, la línea de código específica donde encontrarlo o una explicación paso a paso del código. Quizás podría editar su pregunta para aclarar. Si está preguntando por el primero: posible duplicado de ¿Cómo se calcula la dificultad?
¿La dificultad es lo mismo que el objetivo?
La dificultad es esencialmente la representación legible por humanos del objetivo. Ver aquí: ¿Qué es "dificultad" y cómo se relaciona con "objetivo"?

Respuestas (3)

La sección de destino del encabezado del bloque se llama nBits en el código. nBits es una codificación compacta de 32 bits de un umbral objetivo de 256 bits. Funciona como notación científica, excepto que usa base-256 en lugar de base-10. Por ejemplo, si nBits es igual a 0x181b8330, lo calcularía así:

fórmula de n bits

O, más simplemente, usaría la misma abreviatura que usa con la notación científica normal:

nBits rápido

En un punto de re-objetivo (cada bloque 2016), Bitcoin Core ajusta los nBits de acuerdo con las reglas descritas en esta respuesta , excepto que es importante tener en cuenta que cuando la dificultad cambia en un porcentaje p , los nBits se ajustan a la inversa ( -p porcentaje ). Esto se debe a que un objetivo más bajo es más difícil de alcanzar por la forma en que se implementa Bitcoin.

También es importante tener en cuenta que no puede simplemente ajustar la parte del exponente de nBits de la manera obvia porque cuando Satoshi escribió el código por primera vez, heredó de un tipo firmado, por lo que se debe tener especial cuidado de no crear un nBits negativo. valor. La Referencia para desarrolladores de Bitcoin.org tiene más detalles (pero tenga cuidado, aún no he tenido un experto que revise esa sección).

¿Puede explicar cómo es esto Base-256? Seguramente para base 256 necesitaríamos 256 símbolos únicos?
@ElRonnoco Sí tiene 256 símbolos únicos: cada byte es un símbolo. (Para la analogía, de todos modos; la notación exponencial en realidad no requiere que la base se alinee con los símbolos; de hecho, los matemáticos usan mucho la base $e$ ).

No estoy seguro de cómo se implementa esto realmente en el código, pero puede aproximar el nuevo valor objetivo (nBits) con datos del bloque 2016 anterior. Tenga en cuenta que, como se describe anteriormente , nBits es la codificación compacta de 32 bits del valor objetivo de 256 bits.

Aquí se muestra la nueva dificultad (d_new) como:

d_nuevo = d_antiguo * 2 semanas / t_antiguo

donde 'viejo' significa los bloques anteriores de 2016, y t_viejo es el tiempo que tomó encontrar esos bloques anteriores de 2016.

Aquí se muestra d_new de los valores del bloque de génesis como:

d_new = nBits_genesis / nBits_new, y de manera similar
d_old = nBits_genesis / nBits_old

La combinación de estas 3 ecuaciones da como resultado

nBits_nuevo = (t_antiguo / 2 semanas) * nBits_antiguo

Entonces, conociendo las marcas de tiempo del nuevo bloque y el bloque 2016 anterior, y el objetivo del bloque 2016 anterior, podemos aproximarnos al nuevo valor objetivo. Por ejemplo:

bloque 703584
nBits = 0x170e2632 = 927282 * 256^(23-3)
marca de tiempo 2021-10-04 16:35:19

bloque 701568 (el bloque 2016 anterior)
nBits = 0x170ed0eb = 970987 * 256^(23-3)
marca de tiempo 2021-09-21 07:34:36

Entonces
t_old = 13 días 9h 33s = 1155633s y 2 semanas = 1209600s
nBits_old = 970987 * 256^(23-3)
Por lo tanto, el nuevo objetivo es aproximadamente
1155633/1209600 * 256^20
= 0.955384424 * 970987 * 292566 ^ 20

Convirtiendo al formato compacto de 32 bits obtenemos nBits_new ~ 0x170e27b2

La mantisa 927666 (0x0e27b2) está cerca de la mantisa real 927282 (0x0e2632). Es una aproximación razonable, pero obviamente los valores absolutos de los objetivos son bastante diferentes porque es base 256. Es probable que el error aquí se deba al redondeo al segundo más cercano en las marcas de tiempo. Aunque este no es el cálculo explícito realizado en el código, espero que ayude a la comprensión general, incluidas las referencias aquí y aquí .

Tengo una implementación c# en funcionamiento del cálculo de nBits. Lo he probado y funciona. Sin embargo, tenga en cuenta que mi máquina es Little Endian, por lo que la implementación lo tiene en cuenta. Si su máquina es Big Endian, entonces la forma en que leería los bytes de nBits sería diferente. Si no sabe cómo obtener changeFactor, los pasos se encuentran a continuación después del código.

changeFactor es la relación entre el tiempo que llevó minar los últimos 2015 bloques y el tiempo esperado de 10 minutos por bloque. {Por favor, no es un error tipográfico. Son los últimos bloques de 2015 los que tendrá en cuenta al calcular el factor de cambio, aunque solo vuelva a calcular los nBits después de cada bloque de 2016}.

tiempo real de los últimos 2015 bloques = unixEpoch del bloque más alto actual - unixEpoch del bloque con blockHeight es igual a [currentHighestBlockHeight - 2014] {de nuevo, esto no es un error tipográfico}

tiempo esperado = 2016 * 10 * 60 = 1209600

factor de cambio = tiempo actual / tiempo esperado. Sin embargo, hay un límite para el factor de cambio. No puede haber un cambio de más del 400% por ciclo de retarget.

entonces, después de obtener el factor de cambio, haces el ff. para mantenerlo dentro de los límites establecidos antes de enviarlo a la función de retargeting.

if (changeFactor > 4) changeFactor = 4;
if (changeFactor < 0.25) changeFactor = 0.25;

Finalmente, oldNBits son solo los nBits del bloque Highest actual en forma de uint. Espero que esto ayude.

public static uint RetargetByFactor(uint oldNBits, double changeFactor)
        {
            // convert change factor to rational number with numerator and denomenator
            BigInteger numerator = 0;
            BigInteger denomenator = 1;

            while(changeFactor % 1 != 0)
            {
                changeFactor = changeFactor * 10;
                denomenator = denomenator * 10;
            }
            numerator = (BigInteger)changeFactor;

            byte[] oldNBitsBytes = BitConverter.GetBytes(oldNBits);
            byte[] mantissa = new byte[] {oldNBitsBytes[0], oldNBitsBytes[1], oldNBitsBytes[2], 0x00 };  // need to reverse the bytes because we want the mantissa in little endian
            byte exponent = oldNBitsBytes[3];

            BigInteger result = new BigInteger(mantissa);
            result = result << (exponent-3)*8;

            result = result * numerator / denomenator;

            byte[] resultBytes = result.ToByteArray();

            if (result == 0)
            {
                return 0;
            }

            // now to get the exponent of the newNBits, we count how many binary right shifts are needed for result to go below or equal to 0xffffff.
            byte newExponent = 3;
            while(result > 0xffffff)
            {
                result = result >> 8;
                newExponent++;
            }

            BigInteger newMantissa = result;

            List<byte> compressedResult = new List<byte>();
            byte[] newMantissaBytes = newMantissa.ToByteArray();

            
            compressedResult.AddRange(new byte[] { newMantissaBytes[0], newMantissaBytes[1], newMantissaBytes[2] });

            compressedResult.Add(newExponent);

            return BitConverter.ToUInt32(compressedResult.ToArray(), 0);
        }
Finalmente, déjame agregar que solo calculas nBits para todos los bloques cuyo blockHeight % 2016 es igual a cero.