Bitcoin Forum

Local => Новички => Topic started by: epros on November 07, 2013, 11:41:27 AM



Title: Откуда берётся среднее время генерации?
Post by: epros on November 07, 2013, 11:41:27 AM
Вопрос у меня такой: Когда после очередного изменения difficulty (сложности) сгенерировано ровно 2016 блоков, следующий блок должен генерироваться уже с новой сложностью. Принцип её расчёта понятен: Исходя из того, что 2016 блоков в идеале должны генерироваться за две недели (т.е. за 1209600 секунд), мы смотрим, какая была скорость генерации в предшествующий период, и в соответствующее количество раз изменяем сложность. Вопрос, как водится, заключается в деталях. Сложность определяется с точностью не менее 6-ти десятичных знаков, т.е. если я в этот самый момент хочу рассчитать новую сложность, я  должен получить значение ни на миллионную долю не меньше и не больше, чем стандартный алгоритм. Вот я беру последние 2016 блоков, смотрю записанное в их заголовках время генерации (а оно указывается с точностью до секунды), беру разность между временем генерации последнего и первого блоков, рассчитываю отсюда новую сложность и ... получаю совпадение с установленным новым значением сложности не более, чем в четырёх знаках. ??? Что здесь не так? Может алгоритм иначе оценивает время генерации 2016-ти блоков? Например, считает не с точностью до секунды, а округляет до минут? Где можно узнать точный алгоритм оценки среднего времени генерации блока, используемый при расчёте нового значения сложности?


Title: Re: Откуда берётся среднее время генерации?
Post by: awoland on November 07, 2013, 11:52:45 AM
Точный алгоритм есть в исходниках bitcoin-qt. Это и есть эталонная реализация алгоритма.


Title: Re: Откуда берётся среднее время генерации?
Post by: epros on November 07, 2013, 11:59:01 AM
Точный алгоритм есть в исходниках bitcoin-qt. Это и есть эталонная реализация алгоритма.
Может Вы поможете мне в них разобраться? Я уже лазил в какие-то исходники bitcoin на GitHub, в основных принципах разобрался, но вот откуда именно берётся оценка времени генерации - "ни асилил"...


Title: Re: Откуда берётся среднее время генерации?
Post by: bee7 on November 07, 2013, 12:02:24 PM
Все определяется в функции GetNextWorkRequired (https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp). Учитывается не среднее время на блок, а время, потребовавшееся для генерации 2016ти блоков (так ошибка вычислений меньше). Новый target (а не сложность) вычисляется исходя из cотношения LastTarged*ActualTimespan/TargetTimeSpan, где LastTarget - то значение, которое использовалось на момент пересчета, ActualTimespan - фактическое время, потребовавшееся на расчет 2016ти блоков, TargetTimeSpan - численно равен 2 неделям в секундах.


Title: Re: Откуда берётся среднее время генерации?
Post by: epros on November 07, 2013, 12:49:19 PM
Это понятно. Время, как я понял, извлекается в этой строчке кода:
Code:
1170   int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
Но не сходится у меня. ::)

Вот, например, рассмотрим блок 266111 (см. на http://blockexplorer.com), у него время 2013-10-26 02:23:14 и это последний блок со сложностью 19100ab6. Раньше него на 2016 - это блок 264095, его время: 2013-10-16 12:15:18. Разница в секундах: 828476. Отношение к количеству секунд в двух неделях: 0.684917328. Умножаем 0x100ab6 на этот коэффициент, получаем 0x0afcс1. Но у следующего блока сложность 190afc85, а не 190afcс1. Близко, но не точно...


Title: Re: Откуда берётся среднее время генерации?
Post by: bee7 on November 07, 2013, 01:28:50 PM
Ну вы 0x100ab6 сначала отмаcштабируйте на 2^((0x19-3)*8 ), а потом умножайте/делите. После чего результат разделите на 2^((0x19-3)*8 ) . См bignum.h
И вообще, применять плавающую арифметику для проверки целочисленной несовсем корректно, IMHO. Т.е. результат вы получите близкий, но в силу ошибок округления не точный.


Title: Re: Откуда берётся среднее время генерации?
Post by: epros on November 07, 2013, 01:53:46 PM
Ну вы 0x100ab6 сначала отмаcштабируйте на 2^((0x19-3)*8 ), а потом умножайте/делите. После чего результат разделите на 2^((0x19-3)*8 ) . См bignum.h
И вообще, применять плавающую арифметику для проверки целочисленной несовсем корректно, IMHO. Т.е. результат вы получите близкий, но в силу ошибок округления не точный.
Нет, это не ошибка округления. Масштабирование/размасштабирование на 2^((0x19-3)*8 )  - это лишнее, ибо в данном случае это сводится к дописыванию справа 44-х нулей, а потом к удалению этих же самых нулей из результата.

Я, кажется, разобрался. Если из времени последнего блока вычесть время блока, который раньше на 2015 (а не на 2016!!), то всё сходится (проверил на нескольких примерах). Получается, что в стандартном алгоритме ошибка? Ха, ха...


Title: Re: Откуда берётся среднее время генерации?
Post by: fsb4000 on November 07, 2013, 02:01:35 PM
у тебя ошибка. ты сначала считал 2017 блоков. 2016 блоков они все блоки с одной сложностью.
Между  266111  и 264095 2017 блоков. (266111 - 264095 +1 = 2017)
Нужно считать между 266111 264096 (266111 - 264095 +1 = 2016)

P.S. +1 нужно добавлять, потому что иначе мы не учитываем первый блок. Вот пример, показывающий почему нужно добавлять 1, если бы блоки были от 1 до 10, то количество блоков : 10 - 1 +1 = 10


Title: Re: Откуда берётся среднее время генерации?
Post by: bee7 on November 07, 2013, 02:03:08 PM
Нет, это не ошибка округления. Масштабирование/размасштабирование на 2^((0x19-3)*8 )  - это лишнее, ибо в данном случае это сводится к дописыванию справа 44-х нулей, а потом к удалению этих же самых нулей из результата.
Вы это серьёзно? Ну-ну.


Я, кажется, разобрался. Если из времени последнего блока вычесть время блока, который раньше на 2015 (а не на 2016!!), то всё сходится (проверил на нескольких примерах). Получается, что в стандартном алгоритме ошибка? Ха, ха...

Алгоритм берет последние 2016 блоков (см исходники). Если вы видите там ошибку - обоснуйте и обратитесь к девелоперам. Я продолжение этой дискуссии для себя считаю пустой тратой времени.


Title: Re: Откуда берётся среднее время генерации?
Post by: epros on November 07, 2013, 02:09:57 PM
у тебя ошибка. ты сначала считал 2017 блоков. 2016 блоков они все блоки с одной сложностью.
Между  266111  и 264095 2017 блоков. (266111 - 264095 +1 = 2017)
Нужно считать между 266111 264096 (266111 - 264095 +1 = 2016)

P.S. +1 нужно добавлять, потому что иначе мы не учитываем первый блок. Вот пример, показывающий почему нужно добавлять 1, если бы блоки были от 1 до 10, то количество блоков : 10 - 1 +1 = 10
Ой, не путайте. Никакого "+1" не надо. (Время 266111-ого) - (Время 264095-ого) - это время генерации 2016-ти блоков: Начиная с 264096-ого (264095-ой не входит) и по 266111-ый включительно.

Нет, это не ошибка округления. Масштабирование/размасштабирование на 2^((0x19-3)*8 )  - это лишнее, ибо в данном случае это сводится к дописыванию справа 44-х нулей, а потом к удалению этих же самых нулей из результата.
Вы это серьёзно? Ну-ну.
Абсолютно. Разве что могу уточнить, что удалять из результата нужно будет 44 цифры (16-ти-ричных), а не обязательно нулей.


Алгоритм берет последние 2016 блоков (см исходники). Если вы видите там ошибку - обоснуйте и обратитесь к девелоперам. Я продолжение этой дискуссии для себя считаю пустой тратой времени.
Да начхать мне на ошибки. Тем более, что ошибка не критичная и теперь исправлять её уже точно никто не будет (иначе старые клиенты с исправленными друг друга не поймут). Просто надо будет иметь это в виду при собственных расчётах.


Title: Re: Откуда берётся среднее время генерации?
Post by: yurm on November 07, 2013, 11:57:53 PM
Это понятно. Время, как я понял, извлекается в этой строчке кода:
Code:
1170   int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
Но не сходится у меня. ::)
Так там же пятью строчками выше ясно написано:
Code:
1165    for (int i = 0; pindexFirst && i < nInterval-1; i++)
1166        pindexFirst = pindexFirst->pprev;
Обратите внимание на -1. Берётся разница между временами первого и последнего блока, сгенерированных при одной и той же сложности. Соответственно, время, прошедшее между генерацией "пограничных" блоков (с разной сложностью), как бы выпадает (не оказывает влияния на сложность). Не знаю точно причин, но подозреваю, что это by design так.


Title: Re: Откуда берётся среднее время генерации?
Post by: epros on November 08, 2013, 06:43:03 AM
Обратите внимание на -1. Берётся разница между временами первого и последнего блока, сгенерированных при одной и той же сложности. Соответственно, время, прошедшее между генерацией "пограничных" блоков (с разной сложностью), как бы выпадает (не оказывает влияния на сложность). Не знаю точно причин, но подозреваю, что это by design так.
Да, спасибо, я уже понял. Вряд ли в этом "-1" есть какой-то практический смысл, скорее, это просто мелкая ошибка разработчика, которая теперь навечно войдёт в историю.  ;)
К сожалению, мне теперь в собственной программе придётся учитывать, что при смене сложности из расчёта выпадает время генерации одного блока. Т.е., скажем, в базе с историческими данными майнинга придётся хранить не по одному параметру DATETIME на каждый момент смены сложности, а по два.


Title: Re: Откуда берётся среднее время генерации?
Post by: bee7 on November 08, 2013, 08:25:22 AM
Обратите внимание на -1. Берётся разница между временами первого и последнего блока, сгенерированных при одной и той же сложности. Соответственно, время, прошедшее между генерацией "пограничных" блоков (с разной сложностью), как бы выпадает (не оказывает влияния на сложность). Не знаю точно причин, но подозреваю, что это by design так.
Да, спасибо, я уже понял. Вряд ли в этом "-1" есть какой-то практический смысл, скорее, это просто мелкая ошибка разработчика, которая теперь навечно войдёт в историю.  ;)
К сожалению, мне теперь в собственной программе придётся учитывать, что при смене сложности из расчёта выпадает время генерации одного блока. Т.е., скажем, в базе с историческими данными майнинга придётся хранить не по одному параметру DATETIME на каждый момент смены сложности, а по два.

Эта "ошибка" позволяет сделать самый первый пересчет сложности в блокчейне. Для биткоина это не актуально было, думаю, что у Сатоши пересчет был "отключен", потому что намайнил он за месяц работы в январе 2009го дофига и небыло ни одного пересчета, но актуально для форков (NMC и пр). Проблема в том, что генезис блок содержит таймстамп, не имеющий отношения к рассчтету блоков никакого, т.е. период на генерацию самого первого блока  посчитать таким образом невозможно.

Насчет нужно ли брать TargetTimeSpan на 1 блок меньше в таком случае, нужно подумать (с математической точки зрения - да, нужно, может есть какой-то другой смысл в этом)


Title: Re: Откуда берётся среднее время генерации?
Post by: epros on November 08, 2013, 05:25:27 PM
Эта "ошибка" позволяет сделать самый первый пересчет сложности в блокчейне.
Для первого пересчёта можно было сделать отдельное исключение в коде.

Для биткоина это не актуально было
Наверное не так уж принципиально, что алгоритм подгоняет сложность под эталон "2015 блоков за две недели" вместо задуманного "2016 блоков за две недели". Правда тот факт, что начало периода оценки не совпадает с моментом предыдущего переключения сложности, создаёт некоторые неудобства. Об этом, вероятно, просто не подумали. Но теперь уж придётся принимать то, что есть.


Title: Re: Откуда берётся среднее время генерации?
Post by: bee7 on November 08, 2013, 06:46:19 PM
Эта "ошибка" позволяет сделать самый первый пересчет сложности в блокчейне.
Для первого пересчёта можно было сделать отдельное исключение в коде.

Для биткоина это не актуально было
Наверное не так уж принципиально, что алгоритм подгоняет сложность под эталон "2015 блоков за две недели" вместо задуманного "2016 блоков за две недели". Правда тот факт, что начало периода оценки не совпадает с моментом предыдущего переключения сложности, создаёт некоторые неудобства. Об этом, вероятно, просто не подумали. Но теперь уж придётся принимать то, что есть.

Да, теперь это не исправить: GetNextWorkRequired вызывается из AcceptBlock, которая, в свою очередь, используется для любого внесения блоков в чейн, в том числе, при синхронизации и работе с сетью.