Хватит качать и хранить нули

в 19:29, , рубрики: Lua, md4, Peer-to-Peer, rhash, sha1, tree tiger hash, децентрализованные сети

Скачиваемый файл заполнен нулями

Нуль-блоками я называю блоки(части файла) заполненные нулевыми байтами. Можно заранее посчитать их хеши и не запрашивать эти блоки у источников а сразу помечать их уже загруженными.

Нуль-блоки не надо хранить на диске. Благодаря sparse флагу операционная система просто помечает этот участок файла как заполненный нулями и не хранит эти нули на диске.

Свойства файла заполненного нулями

Файл размером 16MB занимает на диске 4KB

Также показывая что участки скачиваемого файла заполнены нулями можно мотивировать пользователя отказаться от скачивания и распространения битого файла. В моей версии Shareaza эти участки помечаются красной полосой сверху на полосе прогресса загрузки файла.

Откуда берутся нуль-блоки в файле

  1. Раздающий не дождался полного скачивания и проверки файла и выложил неполный(partial) файл.
  2. Результат повреждения сектора диска раздающего.

Это те варианты которые пришли в голову.

Почему эти файлы продолжают распространяться

  1. Видео/аудио файл может иметь нуль-блок в середине и спокойно воспроизводится просто перескакивая то место где попался нуль-блок. Тем самым он может казаться целым.
  2. Образ диска также может иметь нуль-блоки в разных местах и это проявит себя только при попытке чтения файлов из этих блоков.

Как это работает

  1. Перед загрузкой файла p2p клиент получает от источника список хешей блоков.
  2. Каждый хеш из списка сравнивается с заранее вычисленными хешами нуль-блоков.
  3. Те блоки у которых хеш совпал с хешем нуль-блока помечаются уже загруженными. Пользователю дополнительно отображается что в этом месте одни нули.

Инструменты для вычисления нуль-блоков

  1. RHash — он будет непосредственно считать хеши.
  2. Lua — будет загружать в RHash необходимое количество нулей и выводить результаты.
  3. Общие функции скрипта:

    local lua = "lua5.1"                  -- интерпретатор
    local script_name = "zero-block-hash" -- название скрипта (имя файла без расширения)
    
    -- декодирует строку из hex в бинарное представление
    -- https://stackoverflow.com/a/9140231
    function string.fromhex(str)
        return (str:gsub('..', function (cc)
            return string.char(tonumber(cc, 16))
        end))
    end
    
    -- выводит в io.stdout заданное количество нулей
    function std_write(size)
        index = index or 0;
    
        local buffer_size = 1024*1024*16;
    
        if ( size <= buffer_size ) then
            io.stdout:write( (''):rep( size  ) );
        else
            local zero_buffer = (''):rep( buffer_size );
    
            local count = math.floor( size / #zero_buffer );
            local tail = math.fmod( size, #zero_buffer );
    
            for i = 1, count do
                io.stdout:write( zero_buffer );
            end
    
            if ( tail > 0 ) then
                io.stdout:write( zero_buffer:sub( 1, tail ) );
            end
        end
    end

Не качаем нули из сети EDonkey2000

md4(block_data)

ED2K хеш самый простой. У него фиксированный размер блока 9728000 байт. Блоки обрабатываются функцией md4. Понадобится вычислить только одно значение хеша.

Считаем md4 хеш:

--ED2K zero block
local md4_cmd = lua..' -l"'..script_name..'" -e"std_write(9728000);"|rhash -p"%x{md4}" -';

function gen_md4_hash()
    -- запускаем функцию std_write которая передаёт в RHash необходимое количество нулевых байт.
    local md4 = io.popen(md4_cmd, "rb");

    -- получаем результат вычислений
    local hash = md4:read("*a"):upper(); 

    -- выводим результат
    print("")
    print("// md4_hash")
    print("// Hash: "..hash, "Size: 9728000");
    md4:close();
end

Запускаем:

lua5.1 -l "zero-block-hash" -e"gen_md4_hash()"

Результат:

// md4_hash
// Hash: D7DEF262A127CD79096A108E7A9FC138       Size: 9728000

MD4 от 9728000 нулевых байт: D7DEF262A127CD79096A108E7A9FC138

Детектор ED2K нуль-блока Shareaza:

BOOL CED2K::IsZeroBlock(uint32 nBlock) const
{
    // Hash: D7DEF262A127CD79096A108E7A9FC138      Size: 9728000
    static const uint32 ZeroHash[ 4 ] = { 0x62F2DED7, 0x79CD27A1, 0x8E106A09, 0x38C19F7A };
    return memcmp( &ZeroHash, m_pList[ nBlock ].data, sizeof( ZeroHash ) ) == 0;
}

GitHub: ED2K.cpp#L334

Не качаем нули из сети BitTorrent

С BitTorrent посложнее. Минимальный размер блока у BitTorrent это 16384 байт. Далее размер блока удваивается.

Хеш блока это результат работы функции SHA1 над данными блока:

sha1(block_data)

Считаем sha1 хеши:

--Bittorrent zero block
local sha1_cmd = lua..' -l"'..script_name..'" -e"std_write(%s);"|rhash -p"%%x{sha1}" -';

function gen_sha1_hashes(hash_count)
    local size = 16384 -- минимальный размер блока
    local sha1 = {};
    hash_count = hash_count or 13; -- по умолчанию считаем 13 хешей

    -- параллельные вычисления
    -- запускаем счёт хешей передавая размер блока в std_write
    for i = 1, hash_count do
        sha1[i] = io.popen(sha1_cmd:format(size), "rb");
        size = size * 2;
    end

    size = 16384
    -- получаем результаты
    print("")
    print("// sha1_hashes")
    for i = 1, #sha1 do
        local hash = sha1[i]:read("*a"):upper();
        sha1[i]:close();
        print( "// Hash: " .. hash .. "tSize: " .. size );
        size = size * 2;
    end
end

Запускаем:

lua5.1 -l "zero-block-hash" -e"gen_sha1_hashes()"

Мне терпения хватило дождаться вычисления 22 нуль-блоков. Но и этого с избытком. С трудом представляю себе торрент с блоком в 34GB:

// sha1_hashes
// Hash: 897256B6709E1A4DA9DABA92B6BDE39CCFCCD8C1       Size: 16384
// Hash: 5188431849B4613152FD7BDBA6A3FF0A4FD6424B       Size: 32768
// Hash: 1ADC95BEBE9EEA8C112D40CD04AB7A8D75C4F961       Size: 65536
// Hash: 67DFD19F3EB3649D6F3F6631E44D0BD36B8D8D19       Size: 131072
// Hash: 2E000FA7E85759C7F4C254D4D9C33EF481E459A7       Size: 262144
// Hash: 6A521E1D2A632C26E53B83D2CC4B0EDECFC1E68C       Size: 524288
// Hash: 3B71F43FF30F4B15B5CD85DD9E95EBC7E84EB5A3       Size: 1048576
// Hash: 7D76D48D64D7AC5411D714A4BB83F37E3E5B8DF6       Size: 2097152
// Hash: 2BCCBD2F38F15C13EB7D5A89FD9D85F595E23BC3       Size: 4194304
// Hash: 5FDE1CCE603E6566D20DA811C9C8BCCCB044D4AE       Size: 8388608
// Hash: 3B4417FC421CEE30A9AD0FD9319220A8DAE32DA2       Size: 16777216
// Hash: 57B587E1BF2D09335BDAC6DB18902D43DFE76449       Size: 33554432
// Hash: 44FAC4BEDDE4DF04B9572AC665D3AC2C5CD00C7D       Size: 67108864
// Hash: BA713B819C1202DCB0D178DF9D2B3222BA1BBA44       Size: 134217728
// Hash: 7B91DBDC56C5781EDF6C8847B4AA6965566C5C75       Size: 268435456
// Hash: 5B088492C9F4778F409B7AE61477DEC124C99033       Size: 536870912
// Hash: 2A492F15396A6768BCBCA016993F4B4C8B0B5307       Size: 1073741824
// Hash: 91D50642DD930E9542C39D36F0516D45F4E1AF0D       Size: 2147483648
// Hash: 1BF99EE9F374E58E201E4DDA4F474E570EB77229       Size: 4294967296
// Hash: BCC8C0CA9E402EEE924A6046966D18B1F66EB577       Size: 8589934592
// Hash: DC44DD38511BD6D1233701D63C15B87D0BD9F3A5       Size: 17179869184
// Hash: 7FFB233B3B2806328171FB8B5C209F48DC095B72       Size: 34359738368

Детектор BitTorrent нуль-блока в Shareaza

BOOL CBTInfo::IsZeroBlock(uint32 nBlock) const
{
    static const uint32 ZeroHash[22][5] = {
        // Hash: 897256B6709E1A4DA9DABA92B6BDE39CCFCCD8C1       Size: 16384
        { 0xB6567289, 0x4D1A9E70, 0x92BADAA9, 0x9CE3BDB6, 0xC1D8CCCF },
        // Hash: 5188431849B4613152FD7BDBA6A3FF0A4FD6424B       Size: 32768
        { 0x18438851, 0x3161B449, 0xDB7BFD52, 0x0AFFA3A6, 0x4B42D64F },
        // Hash: 1ADC95BEBE9EEA8C112D40CD04AB7A8D75C4F961       Size: 65536
        { 0xBE95DC1A, 0x8CEA9EBE, 0xCD402D11, 0x8D7AAB04, 0x61F9C475 },
        // Hash: 67DFD19F3EB3649D6F3F6631E44D0BD36B8D8D19       Size: 131072
        { 0x9FD1DF67, 0x9D64B33E, 0x31663F6F, 0xD30B4DE4, 0x198D8D6B },
        // Hash: 2E000FA7E85759C7F4C254D4D9C33EF481E459A7       Size: 262144
        { 0xA70F002E, 0xC75957E8, 0xD454C2F4, 0xF43EC3D9, 0xA759E481 },
        // Hash: 6A521E1D2A632C26E53B83D2CC4B0EDECFC1E68C       Size: 524288
        { 0x1D1E526A, 0x262C632A, 0xD2833BE5, 0xDE0E4BCC, 0x8CE6C1CF },
        // Hash: 3B71F43FF30F4B15B5CD85DD9E95EBC7E84EB5A3       Size: 1048576
        { 0x3FF4713B, 0x154B0FF3, 0xDD85CDB5, 0xC7EB959E, 0xA3B54EE8 },
        // Hash: 7D76D48D64D7AC5411D714A4BB83F37E3E5B8DF6       Size: 2097152
        { 0x8DD4767D, 0x54ACD764, 0xA414D711, 0x7EF383BB, 0xF68D5B3E },
        // Hash: 2BCCBD2F38F15C13EB7D5A89FD9D85F595E23BC3       Size: 4194304
        { 0x2FBDCC2B, 0x135CF138, 0x895A7DEB, 0xF5859DFD, 0xC33BE295 },
        // Hash: 5FDE1CCE603E6566D20DA811C9C8BCCCB044D4AE       Size: 8388608
        { 0xCE1CDE5F, 0x66653E60, 0x11A80DD2, 0xCCBCC8C9, 0xAED444B0 },
        // Hash: 3B4417FC421CEE30A9AD0FD9319220A8DAE32DA2       Size: 16777216
        { 0xFC17443B, 0x30EE1C42, 0xD90FADA9, 0xA8209231, 0xA22DE3DA },
        // Hash: 57B587E1BF2D09335BDAC6DB18902D43DFE76449       Size: 33554432
        { 0xE187B557, 0x33092DBF, 0xDBC6DA5B, 0x432D9018, 0x4964E7DF },
        // Hash: 44FAC4BEDDE4DF04B9572AC665D3AC2C5CD00C7D       Size: 67108864
        { 0xBEC4FA44, 0x04DFE4DD, 0xC62A57B9, 0x2CACD365, 0x7D0CD05C },
        // Hash: BA713B819C1202DCB0D178DF9D2B3222BA1BBA44       Size: 134217728
        { 0x813B71BA, 0xDC02129C, 0xDF78D1B0, 0x22322B9D, 0x44BA1BBA },
        // Hash: 7B91DBDC56C5781EDF6C8847B4AA6965566C5C75       Size: 268435456
        { 0xDCDB917B, 0x1E78C556, 0x47886CDF, 0x6569AAB4, 0x755C6C56 },
        // Hash: 5B088492C9F4778F409B7AE61477DEC124C99033       Size: 536870912
        { 0x9284085B, 0x8F77F4C9, 0xE67A9B40, 0xC1DE7714, 0x3390C924 },
        // Hash: 2A492F15396A6768BCBCA016993F4B4C8B0B5307       Size: 1073741824
        { 0x152F492A, 0x68676A39, 0x16A0BCBC, 0x4C4B3F99, 0x07530B8B },
        // Hash: 91D50642DD930E9542C39D36F0516D45F4E1AF0D       Size: 2147483648
        { 0x4206D591, 0x950E93DD, 0x369DC342, 0x456D51F0, 0x0DAFE1F4 },
        // Hash: 1BF99EE9F374E58E201E4DDA4F474E570EB77229       Size: 4294967296
        { 0xE99EF91B, 0x8EE574F3, 0xDA4D1E20, 0x574E474F, 0x2972B70E },
        // Hash: BCC8C0CA9E402EEE924A6046966D18B1F66EB577       Size: 8589934592
        { 0xCAC0C8BC, 0xEE2E409E, 0x46604A92, 0xB1186D96, 0x77B56EF6 },
        // Hash: DC44DD38511BD6D1233701D63C15B87D0BD9F3A5       Size: 17179869184
        { 0x38DD44DC, 0xD1D61B51, 0xD6013723, 0x7DB8153C, 0xA5F3D90B },
        // Hash: 7FFB233B3B2806328171FB8B5C209F48DC095B72       Size: 34359738368
        { 0x3B23FB7F, 0x3206283B, 0x8BFB7181, 0x489F205C, 0x725B09DC }
    };

    int i = 0;
    for(; m_nBlockSize > ( (uint64) 16384 << i ); i++)
        if ( i > 21 )
            return FALSE;

    return memcmp( &m_pBlockBTH[ nBlock ], ZeroHash[ i ], sizeof( ZeroHash[ i ] ) ) == 0;
}

GitHub: BTInfo.cpp#L1611

Не качаем нули из сетей DirectConnect, Gnutella и Gnutella2

Эти три сети используют Tree Tiger Hash (TTH). Исходя из названия это дерево хешей а для вычисления используется функция Tiger. Я такие типы хешей называю "деревянные". TTH на мой взгляд самое простое дерево и благодаря его свойствам мы очень быстро можем вычислить хеш для разных размеров блока.

Минимальный размер блока у TTH это 1024 байта. Далее размер блока удваивается на каждом уровне.

Вычисляется он так:

Tiger(0x00 + block_data)

0x00 — байт префикс Leaf блока
block_data — данные блока(в нашем случае это 1024 нулевых байта)
+ — конкатенация
Tiger — хеш функция

Далее для того чтобы вычислить нуль-блоки большего размера мы используем хеш от нуль-блока меньшего размера.

Tiger(0x01 + hash + hash)

0x01 — байт префикс для пары хешей
hash — хеш нуль-блока который мы получили на предыдущем уровне.
Tiger — хеш функция

Пишем функции для вычисления:

--Tiger Tree Hash Leaf block
local leaf_hash_cmd = lua..' -l"'..script_name..'" -e"std_write_leaf_hash()"';

--Tiger Tree Hash Internal block
local internal_hash_cmd = lua..' -l"'..script_name..'" -e"std_write_internal_hash('%s')"';

-- передаёт в rhash нуль-блок с префиксом ''  
function std_write_leaf_hash()
    local tiger = io.popen('rhash -p"%x{tiger}" -', "wb") 
    tiger:write(''..(''):rep(1024))
    tiger:close()
end

-- передаёт в rhash пару одинаковых хешей с префиксом '1'
function std_write_internal_hash(hash)
    local tiger = io.popen('rhash -p"%x{tiger}" -', "wb");
    hash = hash:fromhex();
    tiger:write('1'..hash..hash)
    tiger:close()
end

-- хеш от нуль-блока
function tth_leaf()
    local rhash = io.popen(leaf_hash_cmd, "rb");
    local hash = rhash:read("*a");
    rhash:close();
    return hash;
end

-- хеш от пары одинаковых хешей
function tth_root(hash_hex)
    local rhash = io.popen(internal_hash_cmd:format(hash_hex), "rb");
    local hash = rhash:read("*a");
    rhash:close();
    return hash;
end

-- вычисляем заданное количество хешей
function gen_tth_hashes(hash_count)
    -- получаем хеш от нуль-блока
    local hash_hex = tth_leaf():upper();
    hash_count = hash_count or 37;
    hash_count = hash_count - 1;
    print("")
    print("// tth_hashes")
    for i = 0, hash_count do
        print("// Hash: "..hash_hex, " Size: "..(1024*2^i));
         -- получаем хеш от нуль-блока вдвое большего размера
        hash_hex = tth_root(hash_hex):upper();
    end
end

Запускаем:

lua5.1 -l "zero-block-hash" -e"gen_tth_hashes()"

В результате я очень быстро получил 37 нуль-блоков. Дальше были проблемы с отображением размера блока у скрипта. Но и этих значений с избытком. Последний блок размером в 70TB.

// tth_hashes
// Hash: 13143C45D95485EACD9C47D72630EF0139436CB77DF2632B        Size: 1024
// Hash: 855DCE7FE3E963F50295A673120E6259165CED9F086DB031        Size: 2048
// Hash: 38FB763B44ECA3B13F40182C75694360AC8DA0865DDB29D6        Size: 4096
// Hash: 721BEF53CBBDA47BE44BD26C43EC048F136D371E918200CF        Size: 8192
// Hash: AFDDF505C1E1D5AF8FAE007BBE4E64578F34D912345E23D8        Size: 16384
// Hash: 53CC478ED14FF7FB671F94ECE0FD7C8C5DCB2FE611ACAC6B        Size: 32768
// Hash: 098B212D6EE0398D319D4F1807E87235A0B8665BA46EF77F        Size: 65536
// Hash: 69940A3C20C43576D258BD210339565711D696E94A3511EB        Size: 131072
// Hash: FA4317C074C2D7CD9BBFD7F4C8BD3F9F79F330F0C27B61B8        Size: 262144
// Hash: AF8E46E049A800C2339E863AF390C5CFF02BCC39025D44AA        Size: 524288
// Hash: 650022207EA4EB454E24D3279539F3CCD92F034E2F83CCB7        Size: 1048576
// Hash: 0BED4DF002309E7D33D52ED0D5C3C24B1ECAA330CBAFB723        Size: 2097152
// Hash: 2FFF449E538E158CD346C5BF7778F2FF67383707955C72C1        Size: 4194304
// Hash: F2D3852A12C25C0C1EE124C07144C6CFA3CD0E72DB9364F8        Size: 8388608
// Hash: 8E6FD02F7F9A0D5233E9287C6D139D44DE76BB80BCBD8BEC        Size: 16777216
// Hash: F98C3CB14C4B501DCEF346D6FB92E56AC3F96102B17468F4        Size: 33554432
// Hash: 1830D2019F1A54C7A8A3947E36D34A4E676523FF0735E0FC        Size: 67108864
// Hash: 3D002613BA2F88DA7D7E1AB165677FC939B5EC6FFD5D2E73        Size: 134217728
// Hash: BC0466EE7A0C30E31EFD803598BE8F69400B96AE3126AF70        Size: 268435456
// Hash: 31D3A13D9F1BD0D2E16FF2BF6749F830D81693D63E4C1903        Size: 536870912
// Hash: 6EF9A41AEC7C0C0B821D3A845994E6F18E5268E37BC982C1        Size: 1073741824
// Hash: 13132A77BAB0B8A0130FC2B5BF6C36701C622A36AFFBD175        Size: 2147483648
// Hash: E684CA0E3D759457F3F2B4183A0889B25C49F70AB5B5AD8E        Size: 4294967296
// Hash: 8C4AEAB1D5A2E3ABBD19848EBC9813121A83D196320EFE54        Size: 8589934592
// Hash: 2CB4627DB09C230212258BAD4120AA0A1C4A185BD2CC4C57        Size: 17179869184
// Hash: B58DE81DC064E964720A0C181AE6EF415F865BAA18E9F019        Size: 34359738368
// Hash: EC0B596EFA9EDBEFE275539914F30757E2E3EB82C30B6FB8        Size: 68719476736
// Hash: BA0078DAD436099159ADA9CFA1457806EB581730364084E0        Size: 137438953472
// Hash: D96DA2416DBF7DAC663872838F8F4E7D8E7C4D2D2A2051AB        Size: 274877906944
// Hash: 74816B22B67E4E6995FECAEB84302D01E489BCD76845444B        Size: 549755813888
// Hash: 307DB672C03531EB0E9B19FC2ED134ACCEFFB4E04D8EB62D        Size: 1099511627776
// Hash: 43CD6009D7931ECC1FFC484D8156A92EC673DEF3D6AE7CF9        Size: 2199023255552
// Hash: 84814323435A450426EECC6700349387D61BD5027F6E7085        Size: 4398046511104
// Hash: 05275B3D69A996B1E8ABDA6EACE8605D5BB7DD8964AC4C79        Size: 8796093022208
// Hash: 434934E2D0EFDEE9864982221FB8A0A872D842B4DA6C59E7        Size: 17592186044416
// Hash: 435396F0F684A6B3E5B5940A79800EE384915CCAD7C52385        Size: 35184372088832
// Hash: 7F377469FB6883D13331667F52CF23194846311094A363C4        Size: 70368744177664

Детектор TigerTree нуль-блока в Shareaza

BOOL CTigerTree::IsZeroBlock(uint32 nBlock) const
{
    static const uint64 ZeroHash[37][3] =
    {
        // Hash: 13143C45D95485EACD9C47D72630EF0139436CB77DF2632B        Size: 1024
        { 0xEA8554D9453C1413, 0x01EF3026D7479CCD, 0x2B63F27DB76C4339 },
        // Hash: 855DCE7FE3E963F50295A673120E6259165CED9F086DB031        Size: 2048
        { 0xF563E9E37FCE5D85, 0x59620E1273A69502, 0x31B06D089FED5C16 },
        // Hash: 38FB763B44ECA3B13F40182C75694360AC8DA0865DDB29D6        Size: 4096
        { 0xB1A3EC443B76FB38, 0x604369752C18403F, 0xD629DB5D86A08DAC },
        // Hash: 721BEF53CBBDA47BE44BD26C43EC048F136D371E918200CF        Size: 8192
        { 0x7BA4BDCB53EF1B72, 0x8F04EC436CD24BE4, 0xCF0082911E376D13 },
        // Hash: AFDDF505C1E1D5AF8FAE007BBE4E64578F34D912345E23D8        Size: 16384
        { 0xAFD5E1C105F5DDAF, 0x57644EBE7B00AE8F, 0xD8235E3412D9348F },
        // Hash: 53CC478ED14FF7FB671F94ECE0FD7C8C5DCB2FE611ACAC6B        Size: 32768
        { 0xFBF74FD18E47CC53, 0x8C7CFDE0EC941F67, 0x6BACAC11E62FCB5D },
        // Hash: 098B212D6EE0398D319D4F1807E87235A0B8665BA46EF77F        Size: 65536
        { 0x8D39E06E2D218B09, 0x3572E807184F9D31, 0x7FF76EA45B66B8A0 },
        // Hash: 69940A3C20C43576D258BD210339565711D696E94A3511EB        Size: 131072
        { 0x7635C4203C0A9469, 0x5756390321BD58D2, 0xEB11354AE996D611 },
        // Hash: FA4317C074C2D7CD9BBFD7F4C8BD3F9F79F330F0C27B61B8        Size: 262144
        { 0xCDD7C274C01743FA, 0x9F3FBDC8F4D7BF9B, 0xB8617BC2F030F379 },
        // Hash: AF8E46E049A800C2339E863AF390C5CFF02BCC39025D44AA        Size: 524288
        { 0xC200A849E0468EAF, 0xCFC590F33A869E33, 0xAA445D0239CC2BF0 },
        // Hash: 650022207EA4EB454E24D3279539F3CCD92F034E2F83CCB7        Size: 1048576
        { 0x45EBA47E20220065, 0xCCF3399527D3244E, 0xB7CC832F4E032FD9 },
        // Hash: 0BED4DF002309E7D33D52ED0D5C3C24B1ECAA330CBAFB723        Size: 2097152
        { 0x7D9E3002F04DED0B, 0x4BC2C3D5D02ED533, 0x23B7AFCB30A3CA1E },
        // Hash: 2FFF449E538E158CD346C5BF7778F2FF67383707955C72C1        Size: 4194304
        { 0x8C158E539E44FF2F, 0xFFF27877BFC546D3, 0xC1725C9507373867 },
        // Hash: F2D3852A12C25C0C1EE124C07144C6CFA3CD0E72DB9364F8        Size: 8388608
        { 0x0C5CC2122A85D3F2, 0xCFC64471C024E11E, 0xF86493DB720ECDA3 },
        // Hash: 8E6FD02F7F9A0D5233E9287C6D139D44DE76BB80BCBD8BEC        Size: 16777216
        { 0x520D9A7F2FD06F8E, 0x449D136D7C28E933, 0xEC8BBDBC80BB76DE },
        // Hash: F98C3CB14C4B501DCEF346D6FB92E56AC3F96102B17468F4        Size: 33554432
        { 0x1D504B4CB13C8CF9, 0x6AE592FBD646F3CE, 0xF46874B10261F9C3 },
        // Hash: 1830D2019F1A54C7A8A3947E36D34A4E676523FF0735E0FC        Size: 67108864
        { 0xC7541A9F01D23018, 0x4E4AD3367E94A3A8, 0xFCE03507FF236567 },
        // Hash: 3D002613BA2F88DA7D7E1AB165677FC939B5EC6FFD5D2E73        Size: 134217728
        { 0xDA882FBA1326003D, 0xC97F6765B11A7E7D, 0x732E5DFD6FECB539 },
        // Hash: BC0466EE7A0C30E31EFD803598BE8F69400B96AE3126AF70        Size: 268435456
        { 0xE3300C7AEE6604BC, 0x698FBE983580FD1E, 0x70AF2631AE960B40 },
        // Hash: 31D3A13D9F1BD0D2E16FF2BF6749F830D81693D63E4C1903        Size: 536870912
        { 0xD2D01B9F3DA1D331, 0x30F84967BFF26FE1, 0x03194C3ED69316D8 },
        // Hash: 6EF9A41AEC7C0C0B821D3A845994E6F18E5268E37BC982C1        Size: 1073741824
        { 0x0B0C7CEC1AA4F96E, 0xF1E69459843A1D82, 0xC182C97BE368528E },
        // Hash: 13132A77BAB0B8A0130FC2B5BF6C36701C622A36AFFBD175        Size: 2147483648
        { 0xA0B8B0BA772A1313, 0x70366CBFB5C20F13, 0x75D1FBAF362A621C },
        // Hash: E684CA0E3D759457F3F2B4183A0889B25C49F70AB5B5AD8E        Size: 4294967296
        { 0x5794753D0ECA84E6, 0xB289083A18B4F2F3, 0x8EADB5B50AF7495C },
        // Hash: 8C4AEAB1D5A2E3ABBD19848EBC9813121A83D196320EFE54        Size: 8589934592
        { 0xABE3A2D5B1EA4A8C, 0x121398BC8E8419BD, 0x54FE0E3296D1831A },
        // Hash: 2CB4627DB09C230212258BAD4120AA0A1C4A185BD2CC4C57        Size: 17179869184
        { 0x02239CB07D62B42C, 0x0AAA2041AD8B2512, 0x574CCCD25B184A1C },
        // Hash: B58DE81DC064E964720A0C181AE6EF415F865BAA18E9F019        Size: 34359738368
        { 0x64E964C01DE88DB5, 0x41EFE61A180C0A72, 0x19F0E918AA5B865F },
        // Hash: EC0B596EFA9EDBEFE275539914F30757E2E3EB82C30B6FB8        Size: 68719476736
        { 0xEFDB9EFA6E590BEC, 0x5707F314995375E2, 0xB86F0BC382EBE3E2 },
        // Hash: BA0078DAD436099159ADA9CFA1457806EB581730364084E0        Size: 137438953472
        { 0x910936D4DA7800BA, 0x067845A1CFA9AD59, 0xE0844036301758EB },
        // Hash: D96DA2416DBF7DAC663872838F8F4E7D8E7C4D2D2A2051AB        Size: 274877906944
        { 0xAC7DBF6D41A26DD9, 0x7D4E8F8F83723866, 0xAB51202A2D4D7C8E },
        // Hash: 74816B22B67E4E6995FECAEB84302D01E489BCD76845444B        Size: 549755813888
        { 0x694E7EB6226B8174, 0x012D3084EBCAFE95, 0x4B444568D7BC89E4 },
        // Hash: 307DB672C03531EB0E9B19FC2ED134ACCEFFB4E04D8EB62D        Size: 1099511627776
        { 0xEB3135C072B67D30, 0xAC34D12EFC199B0E, 0x2DB68E4DE0B4FFCE },
        // Hash: 43CD6009D7931ECC1FFC484D8156A92EC673DEF3D6AE7CF9        Size: 2199023255552
        { 0xCC1E93D70960CD43, 0x2EA956814D48FC1F, 0xF97CAED6F3DE73C6 },
        // Hash: 84814323435A450426EECC6700349387D61BD5027F6E7085        Size: 4398046511104
        { 0x04455A4323438184, 0x8793340067CCEE26, 0x85706E7F02D51BD6 },
        // Hash: 05275B3D69A996B1E8ABDA6EACE8605D5BB7DD8964AC4C79        Size: 8796093022208
        { 0xB196A9693D5B2705, 0x5D60E8AC6EDAABE8, 0x794CAC6489DDB75B },
        // Hash: 434934E2D0EFDEE9864982221FB8A0A872D842B4DA6C59E7        Size: 17592186044416
        { 0xE9DEEFD0E2344943, 0xA8A0B81F22824986, 0xE7596CDAB442D872 },
        // Hash: 435396F0F684A6B3E5B5940A79800EE384915CCAD7C52385        Size: 35184372088832
        { 0xB3A684F6F0965343, 0xE30E80790A94B5E5, 0x8523C5D7CA5C9184 },
        // Hash: 7F377469FB6883D13331667F52CF23194846311094A363C4        Size: 70368744177664
        { 0xD18368FB6974377F, 0x1923CF527F663133, 0xC463A39410314648 }
    };

    CSectionLock oLock( &m_pSection );

    if ( nBlock >= m_nBaseUsed ) return FALSE;
    if ( m_nActualHeight < m_nHeight ) return FALSE;

    uint32 nBlockHeight = m_nActualHeight - m_nHeight;

    if ( nBlockHeight > 36 ) return FALSE;

    CTigerNode* pBase = m_pNode + m_nNodeCount - m_nNodeBase + nBlock;
    return memcmp( ZeroHash[ nBlockHeight ], pBase->value, sizeof( pBase->value ) ) == 0;
}

GitHub: TigerTree.cpp#L1298

Хвосты

Хвост это неполный блок в конце файла. Хвост у файла один и мы можем для него индивидуально посчитать хеш если бы он был заполнен нулями. И в случае если хеш хвоста и вычисленный совпадают помечаем его также загруженным.

Ещё не реализовал данную функцию.

Заключение

Надеюсь данную инструкцию возьмут на вооружение и добавят этот функционал в свои peer-to-peer клиенты и в сети будет циркулировать больше полезных данных.

Ссылки

Скрипт: zero-block-hash.lua
Торрент c файлом заполненным нулями: testfile.torrent

Автор: ivan386

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js