Привет Хабр, в 2019 году я разбирался в дистанционном электронном голосовании в МГД, в 2020 у нас было голосование по Конституции, где само голосование прошло хорошо, но номера паспортов неудачно попали в сеть. Ну а в этом году мне, как наблюдателю, удалось получить доступ непосредственно к нодам наблюдения всех 4-ех шардов блокчейна, использовавшегося в федеральном голосовании, получить полный дамп транзакций блокчейна голосования и начать его исследование. Как это было и что из этого вышло - под катом


Как это было

Была сформирована группа с большим и длинным труднозапоминающимся названием, которое никто никогда нигде не мог произнести и запомнить: "Команда технических экспертов Рабочей группы по общественному контролю за ДЭГ и внедрению информационных технологий в избирательный процесс при Координационном совете ОП РФ по общественному контролю за голосованием". Запомнить это название было решительно невозможно ни одному человеку из тех с которыми я разговаривал и поэтому мы сами себя называли группой технического наблюдения.

В четверг (за день до выборов) я был в Общественной Палате, где мне уже должен был быть настроен доступ ко всему. Конечно, как это всегда бывает, когда я туда приехал там доступ еще не был настроен, но в течении 2-3 часов созваниваясь с инженером РосТелеКома и переписываясь в Telegram с ребятами из Waves в итоге после всей цепочки одобрений я таки получил долгожданный доступ. Очень важно было прийти именно в четверг, потому что, насколько я понял, никакие изменения в доступах в пятницу после начала голосования уже были бы невозможны. Я запустил написанную мной программу для наблюдения в количестве 4-ех экземпляров (по одной на каждый шард блокчейна), проверил что всё работает и с чувством выполненного долга ушел из Общественной Палаты. Кстати, Waves в итоге заглянули к нам и рассказывали про внутренее устройство системы и даже показывали технические метрики по блокчену, Kafka и другим компонентам, не скрывая особо ничего, за что им отдельный респект

В пятницу, придя в общественную палату, группе наблюдения удалось потыкать интерфейс наблюдателя за блокчейном (вот тут очень важно не путать его с нодой наблюдения, потому что это не одно и то же), а также посмотреть сайт со статистикой голосования и выгрузками из блокчейна.

Рабочие места для группы технического наблюдения
Рабочие места для группы технического наблюдения

Для самого сайта было решено написать программу которая скачает все эти файлы, финальный вариант которой я выложил в субботу для всех желающих. Это консольная утилита написанная на .NET Core. Сайт stat устроен таким образом, что парсером html страниц его стащить было невозможно, поэтому я "дергал" напрямую API его бэка, "подсмотрев" куда делает обращения браузер во время переходов между страницами. Затем я столкнулся с тем, что система безопасности не даёт делать к этому сайту чересчур много запросов. В результате подобрав время задержки между запросами мне удалось побороть и её. Если вы скачивали файлы - то там должно было получиться 43 199 файла внутри 1691 папок - суммарно почти 9 Гб. Каждая папка - это один избирательный округ.

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

Вечер воскресения - подводятся результаты
Вечер воскресения - подводятся результаты

В итоге к концу голосования у меня были следующие дампы:

  1. Выгрузка с stat-сайта, сделанная с домашнего ноутбука

  2. Запись данных в реальном времени на вечер воскресения и на утро понедельника (по транзакциям они не отличались, потому что после завершения голосования новых транзакций не было, но тем не менее ноды наблюдения были активны всю ночь с воскресения на понедельник)

  3. Выгрузка всего блокчейна на утро понедельника

Предварительная работа

Естественно для того чтобы всё это проделать потребовалась предварительная работа.

Как было сказано выше интерфейс наблюдателя и нода наблюдения - это не одно и то же. Интерфейс наблюдателя - это веб-приложение которое выводит информацию об транзакциях в блокчейне, но оно может получать эту информацию не напрямую из блокчейна, а через промежуточные системы. В то время как нода наблюдения, это компонент самого блокчейна. Она не имеет никакого графического интерфейса и всё общение с ней происходит через API. И для того чтобы наблюдать за блокчейном требуется написать программу, которая будет непрерывно скачивать транзакции с ноды наблюдения и сохранять к себе.

Нода наблюдения для системы Waves предоставляет несколько типов API для взаимодействия с ней. Для того чтобы не сильно нагружать систему был выбран механизм получения событий по подписке через gRPC Streaming.

Нода наблюдения, может присылать следующие события:

  1. Исторические данные до текущего (для блокчейна) момента - AppendedBlockHistory

  2. Данные о накоплению транзакций - MicroBlockAppended

  3. Данные об добавлении накопленных транзакций в блок - BlockAppended

  4. Данные по откату транзакций (в голосовании не должны были использоваться и не использовались, но их тоже добавил - а вдруг)

При подписывании на события нужно выбрать с какого момента необходимо получить данные (генезис,конкретный блок или текущий момент), после чего нода наблюдателя действовала по следующему алгоритму:

  1. Если момент времени находился в прошлом для блокчейна, то начинали отсылаться события AppendedBlockHistory, пока не время не дойдет до текущего момента

  2. В текущий момент времени приходили события по накоплению транзакций MicroBlockAppended, а через какое-то время событие добавления блока BlockAppended

  3. И так происходило до момента отключения

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

Затратив определенное время (где-то две пары выходных на написание кода, тестирование в фоновом режиме и отладка в оставшееся свободное время), была написана программа, которая следила за блокчейном через ноду наблюдателя, и записывала все транзакции в реальном времени. Посколько шардов было 4, то за каждым шардом блокчейна следил отдельный экземпляр программы, потому что так было банально проще. Все транзакции писались в отдельный файл transaction_output.bin, отдельно в sqlite БД сохранялось текущее состояние блокчейна: блоки и транзакции c полями необходимыми для быстрого поиска. При этом полная транзакция записывалась в transaction_output.bin, а в эта БД служила оперативным хранилищем для обработки событий. Важно сказать, что при доступе к блокчейну через ноду наблюдения мы получаем больше информации, чем в файлах с stat-сайта. Например здесь у нас есть информация о блоках, в то время как в экспорте только транзакции. Это даст нам возможность построить некоторые метрики, недоступные напрямую из выгрузки со stat-сайта.

За время тестирования (две недели до голосования) было установлено что нагрузка на программу достаточно маленькая и получение данных прекрасно работает в однозадачном режиме (всё выполняется в рамках одной Task внутри HostedService и не потребовались никакие чудеса распараллеливания). Единственная оптимизация которая  реально оказалась нужна, это объединение в batch-и событий типа AppendedBlockHistory в зависимости от количества транзакций в них. Это связано с тем, что при голосования бывает большое число блоков с небольшим количеством транзакций и когда мы в финале выкачиваем весь блокчейн для сравнения с данными реального времени, нам важно обработать как можно больше таких событий за одну транзакцию БД. Ребята из Waves любезно предоставили возможность подключения к тестовому серверу, чтобы я мог погонять свою программу и отработать разные сценарии её использования.

Исследование данных

Выспавшись за неделю, я приступил к анализу собранных данных. Всю информацию я собрал в БД sqlite. Во-первых для того, чтобы иметь по сути один файл со всей структурированной информацией, во-вторых для того, чтобы другие люди смогли иметь возможность удобно всё это использовать, т.к. формат сохранения транзакций был изначально выбран таким чтобы было удобно транзакции сохранять, а не осуществлять поиск по ним.

Всего я использовал две структуры БД.

Первая база - это расширенная версия БД, использовавшаяся для скачивания файлов транзакций с сайта stat - votings.db3 (в ней сами транзакции были импортированы из файлов внутрь БД и были созданы поля для быстрого поиска)

Вторая база - это БД в которую я импортировал данные из дампа четырёх шардов блокчейна - research.db3

Первая база формируется на основе скачанных файлов и БД метаданных по ним. Она расширяет уже имеющуюся структуру БД написанной мной программы для скачивания файлов с сайта stat, таблицей transaction_in_file в которой размещаются данные из csv-файлов, при этом добавляется отношение 1-ко-многим для таблицы voting_file

Вторая база формируется на основе 4-ех пар файлов (blockchain.db3,transaction_output.bin) из дампа с программ наблюдения. Данные по блокам по сравнению с blockchain.db3 расширяются номером шарда. А для транзакций дополнительно выносятся метки времени, идентификаторы и подпись. Сама транзакций сохраняется в двух форматах: бинарном protobuf (как есть, raw) и json, чтобы всем кто захочет после меня с этим разобраться было легче увидеть общую структуру транзакции в удобном текстовом json-виде.

Загрузка файлов в том формате что представлен на сайте - это далеко не быстрый процесс и чтобы, с одной стороны получить целевое решение, которое напрямую работает с этими файлами без распаковки на диск, а с другой стороны сильно ускорить процесс, я построил конвеер обработки данных. У этого конвеера есть 4 шага:

  1. Загрузка файла целиком в память

  2. Распаковывание csv-файла и чтение информации в объекты

  3. Подготовка группы объектов к batch импорту в БД

  4. Импорт группы объектов в БД

Конвеер построен стандартными средствами .NET на Dataflow. Шаги 1 и 4 выполняются всегда в однопоточном режиме, а шаг 2 - в параллельном. Посколько на моем компьютере 8 логических процессоров и эта операция не содержит операций ввода вывода, а только операции с объектами в памяти, то сверху устанавливается ограничение в 8 максимально исполняющихся задач для этого шага. Дополнительно в шагах устанавливается ограничение в виде 1000 импортируемых файлов в группе. Также накладывается ограничение в виде 5000 одновременно загруженных файлов в память и 5000 одновременно обрабатываемых файлов для того чтобы не занимать слишком много памяти

Загрузку данных шардов делаем немного по-другому.

  1. Вначале читаем информацию из блоков

  2. Читаем файл шарда с его БД целиком в память через проецируемые в память файлы

  3. Считываем транзакции из формата protobuff в объекты и выделяем необходимые поля для БД, дополнительно конвертируем в транзакции в json

  4. Группируем объект для batch импорта в БД

  5. Импортируем группу объектов

Здесь шаг 3 выполняется в многопоточном режиме.

Важное замечание, я старался потратить меньше своего времени поэтому весь код для импорта использует достаточно много оперативной памяти. Во всех случаях были выбраны варианты грузить файлы целиком в память и дальше уже обрабатывать в многопоточном режиме. На ноутбуке 32 Гб памяти, поэтому экономилось самое ценное - время программиста. Тем более что это единоразовый процесс.

Однако с первого раза создать БД не получилось. Оказалось что sqlite при больших запросах создает временные файлы на систеном диске, на котором у меня было свободно всего гигабайт 5. Это поведение конечно же описано в документации, но вечером в понедельник про такое сложно вспомнить.

Принудительно указав в качестве временной папки папку на внешенем SSD всё заработало.

Теперь когда у нас есть уже исследовательские базы, попробуем найти следующую транзакцию из блокчейна в файлах выгрузки. Данное представление получено из Protobuf с помощью стандартного механизма сериализации сообщения в JSON:

Транзакция
{
    "version": 2,
    "executedContractTransaction": {
        "id": "oUI7hiIudzJ5tHwRv9mtKSo9I/T96V2uQNVBzaxPPO0=",
        "senderPublicKey": "YokI3qTb3tVwzFp0Mel8kDkxC9dG1JcPVIm2W261MB2ihglzCCO0P5liyPMJUcOsmY5yk16Zqc9dumSrffpiWg==",
        "tx": {
            "version": 3,
            "createContractTransaction": {
                "id": "mdE3Qgl7+le9XweM5V++gZYfPX+KQE2H5wyfYh5jbxU=",
                "senderPublicKey": "hCWRuHtQC9QlE2XQuHD2BByM66taGJIQhmDvtxNtKu0aZnT/mmbPQWoXesFKy2L6WAqkFRsTb4pvzL5eBKv44g==",
                "image": "voting/voting-contract:v1.5.0",
                "imageHash": "48de795e67a538bbc53da37d622ee69490e0572a43af3818483f302e00cb423d",
                "contractName": "voting-contract",
                "params": [
                    {
                        "key": "pollId",
                        "stringValue": "c6e9ed2a-a972-4701-a67f-321d29523f1d"
                    },
                    {
                        "key": "type",
                        "stringValue": "blind"
                    },
                    {
                        "key": "blindSigModulo",
                        "binaryValue": "yiJKYoVwHEnh0k+lDBl27NUo6JQurRloDedQI4zEIdQL7/gveClkgWZF1jDMNEX3+MgdMHwuxLR1QMiv576MC04a5F0acHgTSb5DRaPnjMaW3OhqFwVpv7I7YmPefIGSl/pHKfFXiI32qGRIlfbOritwNgs5E5iwiEA3DGB7jEOCpKA3kU1EnuYgmtDaqMWTeev+qyZiO3Qia0PzkH8hd4yKtNkFN0tT81FALZo36CX5mdAcoTycJ0ss1iHbNTw+rYiu3v87WaGsBFOiUsZIoIVgwhmipZpStdgQkrkJDyhc2koqq8H8WeA1AmbINjSxTzAnqa847ne4rfo+gMXCM4lDJPCktw4bnmXw6fSBmXSwgLilsy+WKwGmK96NZEHbXfIS3Zq+C5vK8eVmXzTUnYN68G81tVC8PqF213Vh3pYLabEpcwS0f1VDWbzB7+GWRirLN6rrd5mHVoVUZLUn8mOxbhS9W39XKAOfFkrIqqrajOgsTNlphkBwNtAbLcE3sHrFI9TlpP4M1pJPOtM3G8vm+lRpXzHWm2yC5+RAqqjUIvJR9GYESAYcL6jd/988cVxX8RiJs4p/4r1xvNOeA8EABZgCRNpVxDHuqvMHFw03A6Cvi+Mk2fAsWxXV6PQnn0UTzIsywLE/W6ATaIsiFLhAHTg2SY80+VHc1hj5R8E="
                    },
                    {
                        "key": "blindSigExponent",
                        "binaryValue": "AQAB"
                    },
                    {
                        "key": "bulletinHash",
                        "stringValue": "6VZ3SiX5B2U67xJCDaNYDUsjHnLfmU79B8GJHs3HgRAS"
                    },
                    {
                        "key": "dimension",
                        "stringValue": "[[1,3,5]]"
                    },
                    {
                        "key": "votersListRegistrator",
                        "stringValue": "38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"
                    },
                    {
                        "key": "blindSigIssueRegistrator",
                        "stringValue": "38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"
                    },
                    {
                        "key": "issueBallotsRegistrator",
                        "stringValue": "38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"
                    },
                    {
                        "key": "jwtTokenRegistrator",
                        "stringValue": "MIIDVDCCAjygAwIBAgIEU4b7XDANBgkqhkiG9w0BAQUFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE0MDUyOTA5MTgyMFoXDTI0MDUyNjA5MTgyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIOP1eIjY2KwuIAUjOzpQ22Bzaqcn1GJKEaGfhhnE1P1XeO7K0y5YRQA7U3AuBmp4E2Padc6ZtQxju54VUW+iFClrePY8EQKbx9pP76ODZaLum8KmXnoNQVSWURgR+VLZ2eZOYEd6isp7W/kaRt7AFn2UInB+sn6FmwUusqXydBCexjcWngJ+WpI0mDMBceJkVRtqWKPi8to43eV5W1oapzJXurETr0eMu0mrnaltgYO7BP/Ga2BiUQXYDJ+XfNzOrsThIaeMqfEz9/jZ1wMSJHiuCDGgTMM38Pzho20vGv1DJzdRDE+G5F25NM/2P+YLiNh9TK64LCELOlUKK3/Sc8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAI3yE1yF+ldMYM9ZBIeSB0LC2BsfTS7pX8Vl0gFATljnsOzcXPITdjf3pJmyi7B+AMKW6A4JqrMKRBr92FHw7CJccqZ6O5MWjO0ca7oDHXNin+WeyrzNZajkoLXR7Ah1RzGtsFnF/tKGL9ecPfIZG7G6rpt3SknrAcB1rmK+0auDphnvvECkCLx/MzPCbTHdqJC9no7d/IbxYIg57HCv2tQsTJJtRT7TmmQUB0BQf+Hmk7v6dLXaqufB0dx7BTqkKhRJvSXKRyX1LopAB9VHiP8R8EKv/QYoOBlw1EVvrzMaOb6wc7ElkCwdYl6oGSb3CTlSuhcOLsf6gkZGiCeWu3A=="
                    },
                    {
                        "key": "ballotReceivedCert",
                        "stringValue": "38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"
                    },
                    {
                        "key": "servers",
                        "stringValue": "[\"3eEp6svZ9aJguXzoMZNVeybQESrWTxc793ULp4fxsteAyfGMszT4UkV7t2zWZkTwkftAw1UxS4BdcyzodUbMMCTK\"]"
                    }
                ],
                "timestamp": "1631813108420",
                "proofs": [
                    "mGCRyCm7Uytv3xr2+t9qJFZsJql0ZqA4KHlbEsJ7LuF+mJBTrRFFzmpEDrbWAKcQbRnCZDAHm86LlhKdfXl6Eg=="
                ]
            }
        },
        "results": [
            {
                "key": "VOTING_BASE",
                "stringValue": "{\"pollId\":\"c6e9ed2a-a972-4701-a67f-321d29523f1d\",\"bulletinHash\":\"6VZ3SiX5B2U67xJCDaNYDUsjHnLfmU79B8GJHs3HgRAS\",\"dimension\":[[1,3,5]],\"blindSigModulo\":\"ca224a6285701c49e1d24fa50c1976ecd528e8942ead19680de750238cc421d40beff82f782964816645d630cc3445f7f8c81d307c2ec4b47540c8afe7be8c0b4e1ae45d1a70781349be4345a3e78cc696dce86a170569bfb23b6263de7c819297fa4729f157888df6a8644895f6ceae2b70360b391398b08840370c607b8c4382a4a037914d449ee6209ad0daa8c59379ebfeab26623b74226b43f3907f21778c8ab4d905374b53f351402d9a37e825f999d01ca13c9c274b2cd621db353c3ead88aedeff3b59a1ac0453a252c648a08560c219a2a59a52b5d81092b9090f285cda4a2aabc1fc59e0350266c83634b14f3027a9af38ee77b8adfa3e80c5c233894324f0a4b70e1b9e65f0e9f4819974b080b8a5b32f962b01a62bde8d6441db5df212dd9abe0b9bcaf1e5665f34d49d837af06f35b550bc3ea176d77561de960b69b1297304b47f554359bcc1efe196462acb37aaeb77998756855464b527f263b16e14bd5b7f5728039f164ac8aaaada8ce82c4cd96986407036d01b2dc137b07ac523d4e5a4fe0cd6924f3ad3371bcbe6fa54695f31d69b6c82e7e440aaa8d422f251f4660448061c2fa8ddffdf3c715c57f11889b38a7fe2bd71bcd39e03c10005980244da55c431eeaaf307170d3703a0af8be324d9f02c5b15d5e8f4279f4513cc8b32c0b13f5ba013688b2214b8401d3836498f34f951dcd618f947c1\",\"blindSigExponent\":\"10001\",\"status\":\"Active\",\"isRevoteBlocked\":true}"
            },
            {
                "key": "SERVERS",
                "stringValue": "[\"3eEp6svZ9aJguXzoMZNVeybQESrWTxc793ULp4fxsteAyfGMszT4UkV7t2zWZkTwkftAw1UxS4BdcyzodUbMMCTK\"]"
            },
            {
                "key": "VOTERS_LIST_REGISTRATOR",
                "stringValue": "38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"
            },
            {
                "key": "ISSUE_BALLOTS_REGISTRATOR",
                "stringValue": "38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"
            },
            {
                "key": "BLINDSIG_ISSUE_REGISTRATOR",
                "stringValue": "38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"
            },
            {
                "key": "JWTTOKEN_REGISTRATOR",
                "stringValue": "MIIDVDCCAjygAwIBAgIEU4b7XDANBgkqhkiG9w0BAQUFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE0MDUyOTA5MTgyMFoXDTI0MDUyNjA5MTgyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIOP1eIjY2KwuIAUjOzpQ22Bzaqcn1GJKEaGfhhnE1P1XeO7K0y5YRQA7U3AuBmp4E2Padc6ZtQxju54VUW+iFClrePY8EQKbx9pP76ODZaLum8KmXnoNQVSWURgR+VLZ2eZOYEd6isp7W/kaRt7AFn2UInB+sn6FmwUusqXydBCexjcWngJ+WpI0mDMBceJkVRtqWKPi8to43eV5W1oapzJXurETr0eMu0mrnaltgYO7BP/Ga2BiUQXYDJ+XfNzOrsThIaeMqfEz9/jZ1wMSJHiuCDGgTMM38Pzho20vGv1DJzdRDE+G5F25NM/2P+YLiNh9TK64LCELOlUKK3/Sc8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAI3yE1yF+ldMYM9ZBIeSB0LC2BsfTS7pX8Vl0gFATljnsOzcXPITdjf3pJmyi7B+AMKW6A4JqrMKRBr92FHw7CJccqZ6O5MWjO0ca7oDHXNin+WeyrzNZajkoLXR7Ah1RzGtsFnF/tKGL9ecPfIZG7G6rpt3SknrAcB1rmK+0auDphnvvECkCLx/MzPCbTHdqJC9no7d/IbxYIg57HCv2tQsTJJtRT7TmmQUB0BQf+Hmk7v6dLXaqufB0dx7BTqkKhRJvSXKRyX1LopAB9VHiP8R8EKv/QYoOBlw1EVvrzMaOb6wc7ElkCwdYl6oGSb3CTlSuhcOLsf6gkZGiCeWu3A=="
            },
            {
                "key": "BALLOT_RECEIVED_CERT",
                "stringValue": "38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"
            }
        ],
        "resultsHash": "/9vjjH4zD9n7Lf8g2rkI5UZhHLnH7gT54xS90+yjenA=",
        "timestamp": "1631813108821",
        "proofs": [
            "Tx/HPuGAFJLFGxOIlQp3bdXvsu3JBAJw62t7DQ8JMGzt80A4Gc/HQsag3H1CZKl5tk4lmyzm/eO3PFfnEK4z8g=="
        ]
    }
}

Обратите внимание что у в наших данных два timestamp 1631813108420 и 1631813108821, которые описывают два момента времени 2021-09-16 17:25:08 с разницей в ~400 миллисекунд по Гринвичу,

Чтобы найти эту транзакцию в исследовательской БД votings.db3 и получить файл где она находится нужно взять ПЕРВЫЙ timestamp (это который вложенный) и использовать следующий SQL код:

SELECT F.filename
FROM transaction_in_file AS T
INNER JOIN voting_file AS F
ON T.file_id=F.id
INNER JOIN voting AS V
ON F.voting_id=V.id
where T.timestamp=1631813108420

Получается что нужный файл - это BMSQjwfeFpJRz8eKJgmxvAZcv2bGiuuYqvLYHfAZ8wZ6_2021-09-16_2000-2100.zip. Транзакция с временной меткой 2021-09-16 20:25:08 по Москве действительно попадает в этот диапазон!

Искомая транзакция в csv-файле

CSV-запись
BMSQjwfeFpJRz8eKJgmxvAZcv2bGiuuYqvLYHfAZ8wZ6;103;43hTRMyqfip9f5E3RA3TrtuMJMvkziaUrp8iQemW6YanUpVVkkNRujEC6JabdjSgMjfBsSDTMEmPGWKKxpJsLeyw;3;1631813108420;3eEp6svZ9aJguXzoMZNVeybQESrWTxc793ULp4fxsteAyfGMszT4UkV7t2zWZkTwkftAw1UxS4BdcyzodUbMMCTK;0;;[{"key":"pollId","stringValue":"c6e9ed2a-a972-4701-a67f-321d29523f1d"},{"key":"type","stringValue":"blind"},{"key":"blindSigModulo","binaryValue":"yiJKYoVwHEnh0k+lDBl27NUo6JQurRloDedQI4zEIdQL7/gveClkgWZF1jDMNEX3+MgdMHwuxLR1QMiv576MC04a5F0acHgTSb5DRaPnjMaW3OhqFwVpv7I7YmPefIGSl/pHKfFXiI32qGRIlfbOritwNgs5E5iwiEA3DGB7jEOCpKA3kU1EnuYgmtDaqMWTeev+qyZiO3Qia0PzkH8hd4yKtNkFN0tT81FALZo36CX5mdAcoTycJ0ss1iHbNTw+rYiu3v87WaGsBFOiUsZIoIVgwhmipZpStdgQkrkJDyhc2koqq8H8WeA1AmbINjSxTzAnqa847ne4rfo+gMXCM4lDJPCktw4bnmXw6fSBmXSwgLilsy+WKwGmK96NZEHbXfIS3Zq+C5vK8eVmXzTUnYN68G81tVC8PqF213Vh3pYLabEpcwS0f1VDWbzB7+GWRirLN6rrd5mHVoVUZLUn8mOxbhS9W39XKAOfFkrIqqrajOgsTNlphkBwNtAbLcE3sHrFI9TlpP4M1pJPOtM3G8vm+lRpXzHWm2yC5+RAqqjUIvJR9GYESAYcL6jd/988cVxX8RiJs4p/4r1xvNOeA8EABZgCRNpVxDHuqvMHFw03A6Cvi+Mk2fAsWxXV6PQnn0UTzIsywLE/W6ATaIsiFLhAHTg2SY80+VHc1hj5R8E="},{"key":"blindSigExponent","binaryValue":"AQAB"},{"key":"bulletinHash","stringValue":"6VZ3SiX5B2U67xJCDaNYDUsjHnLfmU79B8GJHs3HgRAS"},{"key":"dimension","stringValue":"[[1,3,5]]"},{"key":"votersListRegistrator","stringValue":"38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"},{"key":"blindSigIssueRegistrator","stringValue":"38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"},{"key":"issueBallotsRegistrator","stringValue":"38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"},{"key":"jwtTokenRegistrator","stringValue":"MIIDVDCCAjygAwIBAgIEU4b7XDANBgkqhkiG9w0BAQUFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE0MDUyOTA5MTgyMFoXDTI0MDUyNjA5MTgyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIOP1eIjY2KwuIAUjOzpQ22Bzaqcn1GJKEaGfhhnE1P1XeO7K0y5YRQA7U3AuBmp4E2Padc6ZtQxju54VUW+iFClrePY8EQKbx9pP76ODZaLum8KmXnoNQVSWURgR+VLZ2eZOYEd6isp7W/kaRt7AFn2UInB+sn6FmwUusqXydBCexjcWngJ+WpI0mDMBceJkVRtqWKPi8to43eV5W1oapzJXurETr0eMu0mrnaltgYO7BP/Ga2BiUQXYDJ+XfNzOrsThIaeMqfEz9/jZ1wMSJHiuCDGgTMM38Pzho20vGv1DJzdRDE+G5F25NM/2P+YLiNh9TK64LCELOlUKK3/Sc8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAI3yE1yF+ldMYM9ZBIeSB0LC2BsfTS7pX8Vl0gFATljnsOzcXPITdjf3pJmyi7B+AMKW6A4JqrMKRBr92FHw7CJccqZ6O5MWjO0ca7oDHXNin+WeyrzNZajkoLXR7Ah1RzGtsFnF/tKGL9ecPfIZG7G6rpt3SknrAcB1rmK+0auDphnvvECkCLx/MzPCbTHdqJC9no7d/IbxYIg57HCv2tQsTJJtRT7TmmQUB0BQf+Hmk7v6dLXaqufB0dx7BTqkKhRJvSXKRyX1LopAB9VHiP8R8EKv/QYoOBlw1EVvrzMaOb6wc7ElkCwdYl6oGSb3CTlSuhcOLsf6gkZGiCeWu3A=="},{"key":"ballotReceivedCert","stringValue":"38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"},{"key":"servers","stringValue":"[\"3eEp6svZ9aJguXzoMZNVeybQESrWTxc793ULp4fxsteAyfGMszT4UkV7t2zWZkTwkftAw1UxS4BdcyzodUbMMCTK\"]"}];[{"key":"VOTING_BASE","stringValue":"{\"pollId\":\"c6e9ed2a-a972-4701-a67f-321d29523f1d\",\"bulletinHash\":\"6VZ3SiX5B2U67xJCDaNYDUsjHnLfmU79B8GJHs3HgRAS\",\"dimension\":[[1,3,5]],\"blindSigModulo\":\"ca224a6285701c49e1d24fa50c1976ecd528e8942ead19680de750238cc421d40beff82f782964816645d630cc3445f7f8c81d307c2ec4b47540c8afe7be8c0b4e1ae45d1a70781349be4345a3e78cc696dce86a170569bfb23b6263de7c819297fa4729f157888df6a8644895f6ceae2b70360b391398b08840370c607b8c4382a4a037914d449ee6209ad0daa8c59379ebfeab26623b74226b43f3907f21778c8ab4d905374b53f351402d9a37e825f999d01ca13c9c274b2cd621db353c3ead88aedeff3b59a1ac0453a252c648a08560c219a2a59a52b5d81092b9090f285cda4a2aabc1fc59e0350266c83634b14f3027a9af38ee77b8adfa3e80c5c233894324f0a4b70e1b9e65f0e9f4819974b080b8a5b32f962b01a62bde8d6441db5df212dd9abe0b9bcaf1e5665f34d49d837af06f35b550bc3ea176d77561de960b69b1297304b47f554359bcc1efe196462acb37aaeb77998756855464b527f263b16e14bd5b7f5728039f164ac8aaaada8ce82c4cd96986407036d01b2dc137b07ac523d4e5a4fe0cd6924f3ad3371bcbe6fa54695f31d69b6c82e7e440aaa8d422f251f4660448061c2fa8ddffdf3c715c57f11889b38a7fe2bd71bcd39e03c10005980244da55c431eeaaf307170d3703a0af8be324d9f02c5b15d5e8f4279f4513cc8b32c0b13f5ba013688b2214b8401d3836498f34f951dcd618f947c1\",\"blindSigExponent\":\"10001\",\"status\":\"Active\",\"isRevoteBlocked\":true}"},{"key":"SERVERS","stringValue":"[\"3eEp6svZ9aJguXzoMZNVeybQESrWTxc793ULp4fxsteAyfGMszT4UkV7t2zWZkTwkftAw1UxS4BdcyzodUbMMCTK\"]"},{"key":"VOTERS_LIST_REGISTRATOR","stringValue":"38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"},{"key":"ISSUE_BALLOTS_REGISTRATOR","stringValue":"38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"},{"key":"BLINDSIG_ISSUE_REGISTRATOR","stringValue":"38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"},{"key":"JWTTOKEN_REGISTRATOR","stringValue":"MIIDVDCCAjygAwIBAgIEU4b7XDANBgkqhkiG9w0BAQUFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE0MDUyOTA5MTgyMFoXDTI0MDUyNjA5MTgyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIOP1eIjY2KwuIAUjOzpQ22Bzaqcn1GJKEaGfhhnE1P1XeO7K0y5YRQA7U3AuBmp4E2Padc6ZtQxju54VUW+iFClrePY8EQKbx9pP76ODZaLum8KmXnoNQVSWURgR+VLZ2eZOYEd6isp7W/kaRt7AFn2UInB+sn6FmwUusqXydBCexjcWngJ+WpI0mDMBceJkVRtqWKPi8to43eV5W1oapzJXurETr0eMu0mrnaltgYO7BP/Ga2BiUQXYDJ+XfNzOrsThIaeMqfEz9/jZ1wMSJHiuCDGgTMM38Pzho20vGv1DJzdRDE+G5F25NM/2P+YLiNh9TK64LCELOlUKK3/Sc8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAI3yE1yF+ldMYM9ZBIeSB0LC2BsfTS7pX8Vl0gFATljnsOzcXPITdjf3pJmyi7B+AMKW6A4JqrMKRBr92FHw7CJccqZ6O5MWjO0ca7oDHXNin+WeyrzNZajkoLXR7Ah1RzGtsFnF/tKGL9ecPfIZG7G6rpt3SknrAcB1rmK+0auDphnvvECkCLx/MzPCbTHdqJC9no7d/IbxYIg57HCv2tQsTJJtRT7TmmQUB0BQf+Hmk7v6dLXaqufB0dx7BTqkKhRJvSXKRyX1LopAB9VHiP8R8EKv/QYoOBlw1EVvrzMaOb6wc7ElkCwdYl6oGSb3CTlSuhcOLsf6gkZGiCeWu3A=="},{"key":"BALLOT_RECEIVED_CERT","stringValue":"38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL"}];{"image":"voting/voting-contract:v1.5.0","imageHash":"48de795e67a538bbc53da37d622ee69490e0572a43af3818483f302e00cb423d","contractName":"voting-contract"};1

Важное замечание. Когда бинарные данные представляются в виде текста - это можно сделать несколькими способами. Для программиста есть два знакомых формата представления - hex и base64. Блокчейн добавил еще один формат - base58. По удивительному совпадению у нас тут используются все три. Так в выгрузке stat адреса блокчейна представляется в виде base58, а криптографические константы вроде модуля и экспоненты слепой подписи в hex. Когда мы просим Protobuf сериализовать в транзакцию в JSON (сам Protobuff имеет бинарный сериализатор) то все байтовые последовательности сохраняются в base64. Для того чтобы поиграться в репозитории с исходным кодом есть проект EncodingConverter, который дает возможность переводить один формат в другой.

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

  1. BMSQjwfeFpJRz8eKJgmxvAZcv2bGiuuYqvLYHfAZ8wZ6 при переводе из base58 в base64 превращается в mdE3Qgl7+le9XweM5V++gZYfPX+KQE2H5wyfYh5jbxU= и это то что называется nested_tx_id в csv

  2. 103 - это код типа. 103 - создание, 104 - вызов. Исходный для 103 можно найти в папке creation, а 104 - в папке invocation исходного кода смарт-контрактов (см. VotingMessagesHandler.scala)

  3. 43hTRMyqfip9f5E3RA3TrtuMJMvkziaUrp8iQemW6YanUpVVkkNRujEC6JabdjSgMjfBsSDTMEmPGWKKxpJsLeyw это mGCRyCm7Uytv3xr2+t9qJFZsJql0ZqA4KHlbEsJ7LuF+mJBTrRFFzmpEDrbWAKcQbRnCZDAHm86LlhKdfXl6Eg== (signature - то что в блокчейне называется proof)

  4. 3 - это номер версии

  5. 1631813108420 - метка времени

  6. 3eEp6svZ9aJguXzoMZNVeybQESrWTxc793ULp4fxsteAyfGMszT4UkV7t2zWZkTwkftAw1UxS4BdcyzodUbMMCTK - hCWRuHtQC9QlE2XQuHD2BByM66taGJIQhmDvtxNtKu0aZnT/mmbPQWoXesFKy2L6WAqkFRsTb4pvzL5eBKv44g== это sender_public_key

  7. не используется

  8. не используется (7 и 8 судя по всему относятся к вознаграждению майнеров/комиссии и не нужны нам, да и в файлах они нигде не заполнены)

  9. это входные параметры

  10. это выходные параметры

  11. это дополнительные параметры, которые не вошли в вышеуказанные 9 и 10 (тут например название docker образа смарт-контракта).

Как видите при ручной проверке операции перевода между представлениями байт нужно делать довольно часто - поэтому и была написана небольшая программа для проверки в процессе отладки кода.

Покажу еще обратный процесс как по транзакции в файле найти её в выгрузке. Для этого выберем транзакцию с типом 104

Транзакция
BmFxzLavaz2qhVpkfsXm4j8JqzhmUj5wxVGtvxLf15bi;104;4HnAPSLGwx2NWgMiv3NwEKnXWUExK37WKh2jszUhqUHQfRzjBr1tcMEnWfBmNbd12STKQASrJS6bpFV3XdPHd4MX;4;1631988672987;38yYuGfM5NzpG3P7bPB145ZGvnQJTAPDVKZM2ho7gnytrbeBto9K6cGGx6YDweEaBxMbQXZZCoFYuf4WGUB7iUrL;0;;[{"key":"operation","stringValue":"blindSigIssue"},{"key":"data","stringValue":"[{\"userId\":\"NH7VjMULkBhSEEQ+ctm5ARkjl7XTAKKRZ+jV9XAusS0=\", \"maskedSig\": \"aa93cfef25af25ea9fb6db0d1f073600f7d8f622d0b31b44b8fd1ec2921d15aa0ff2e237ef6f9ab76f2d73ae6c06acaca533aa28dde9996c034d5bc61135782c058f67fb2562f6b1b90f02c20a44d19549da2587e8d3e1bc649da39524835cbc76352480c0546ab0a90b11fb2a68326311cec6a92e9513918b8c215c81d5c50f152610e991d5532fda7fc9cc53fd322f2ae270669656da50af5cbef2647a5664b8c69c7d5e3dda1abb2dfc50040a05b80b6586ca6781337ccc1e6139e7269f75c0fd9287d3bf7c6703e64f9b6fd26ec95b05a484c82474280eafda8dec347f7ef7d0c4c90db03e46e38eeda89008dc77b43228916b4e54bfd1621142349b4ccec8d81cb6b56f0fe1a4ef4a24d3086039eb344b0bf7e4fa8aeaf8a90e4e47c77246e16c254a4a6b6571a49d496538dbe060b83d2c99730d00eedc62029bec9103c34ce015e77ab45141b0160464623a9ad2d2427aa796fae9d36648a1638b6bc1a40e2ce79ade6dcfee320de96bb4a44f3770aa206cc47ed85f28930e0b7ee2278c16f159ef0bcc138ba6a065299ec227d4bf6ed37b43313a22f3126fad06151a0dd686a01855b25ff9961b8712e883292d19a2341f7f7e0deda63502b0e934db7be130cedefb25709d8bab90e9052f7f2665cce91f3cde49767872d7414f4480f531abaaec02eb15405d472a8b8de3ad66281453ebed51712b7ccbfdfd91324e\"}]"}];[{"key":"BLINDSIG_BmFxzLavaz2qhVpkfsXm4j8JqzhmUj5wxVGtvxLf15bi","stringValue":"[{\"userId\":\"NH7VjMULkBhSEEQ+ctm5ARkjl7XTAKKRZ+jV9XAusS0=\",\"maskedSig\":\"aa93cfef25af25ea9fb6db0d1f073600f7d8f622d0b31b44b8fd1ec2921d15aa0ff2e237ef6f9ab76f2d73ae6c06acaca533aa28dde9996c034d5bc61135782c058f67fb2562f6b1b90f02c20a44d19549da2587e8d3e1bc649da39524835cbc76352480c0546ab0a90b11fb2a68326311cec6a92e9513918b8c215c81d5c50f152610e991d5532fda7fc9cc53fd322f2ae270669656da50af5cbef2647a5664b8c69c7d5e3dda1abb2dfc50040a05b80b6586ca6781337ccc1e6139e7269f75c0fd9287d3bf7c6703e64f9b6fd26ec95b05a484c82474280eafda8dec347f7ef7d0c4c90db03e46e38eeda89008dc77b43228916b4e54bfd1621142349b4ccec8d81cb6b56f0fe1a4ef4a24d3086039eb344b0bf7e4fa8aeaf8a90e4e47c77246e16c254a4a6b6571a49d496538dbe060b83d2c99730d00eedc62029bec9103c34ce015e77ab45141b0160464623a9ad2d2427aa796fae9d36648a1638b6bc1a40e2ce79ade6dcfee320de96bb4a44f3770aa206cc47ed85f28930e0b7ee2278c16f159ef0bcc138ba6a065299ec227d4bf6ed37b43313a22f3126fad06151a0dd686a01855b25ff9961b8712e883292d19a2341f7f7e0deda63502b0e934db7be130cedefb25709d8bab90e9052f7f2665cce91f3cde49767872d7414f4480f531abaaec02eb15405d472a8b8de3ad66281453ebed51712b7ccbfdfd91324e\"}]"}];{"contractVersion":1};1

Её timestamp 1631988672987. В базе votings.db3 её можно найти так:

SELECT T.*, F.filename
FROM transaction_in_file AS T
INNER JOIN voting_file AS F
ON T.file_id=F.id
INNER JOIN voting AS V
ON F.voting_id=V.id
where T.timestamp=1631988672987

В базе research.db3 её можно найти так:

SELECT block.height,block.shard, tx.* FROM tx
INNER JOIN block
on tx.block_id=block.id
WHERE nested_timestamp=1631988672987

Откуда мы видим что искомая транзакция находилась в 4-ом шарде и её полное представление:

Транзакция
{
    "version": 2,
    "executedContractTransaction": {
        "id": "XsCzX6RynOCB3hpidZueLiyswcd14+zqyVlWorz1m3U=",
        "senderPublicKey": "4zNGEAmoqMMoRn090G4wtEW9UB9Tf+EXNa9uX6unxHryRM1Zt4ibbJCzQ/Flce2lW+/OuG3yizPr2pSiRD8ggA==",
        "tx": {
            "version": 4,
            "callContractTransaction": {
                "id": "n+tYoNubdg+jUZKN8Kap6EjGyUQDc7k3HzCEIeHDDO0=",
                "senderPublicKey": "aulNNVDJ7mpgSXDDFelmxQxt/cTFMYKWUwuXnXZF0Oz5BMTY1pOBKiw3vaNrlP63tNLGh3tkIcgYh4CUlzR+QQ==",
                "contractId": "ruahrCcUvR4yKs28nzYDTF/Pp+DyOGw1AdO05pKGNec=",
                "params": [
                    {
                        "key": "operation",
                        "stringValue": "blindSigIssue"
                    },
                    {
                        "key": "data",
                        "stringValue": "[{\"userId\":\"NH7VjMULkBhSEEQ+ctm5ARkjl7XTAKKRZ+jV9XAusS0=\", \"maskedSig\": \"aa93cfef25af25ea9fb6db0d1f073600f7d8f622d0b31b44b8fd1ec2921d15aa0ff2e237ef6f9ab76f2d73ae6c06acaca533aa28dde9996c034d5bc61135782c058f67fb2562f6b1b90f02c20a44d19549da2587e8d3e1bc649da39524835cbc76352480c0546ab0a90b11fb2a68326311cec6a92e9513918b8c215c81d5c50f152610e991d5532fda7fc9cc53fd322f2ae270669656da50af5cbef2647a5664b8c69c7d5e3dda1abb2dfc50040a05b80b6586ca6781337ccc1e6139e7269f75c0fd9287d3bf7c6703e64f9b6fd26ec95b05a484c82474280eafda8dec347f7ef7d0c4c90db03e46e38eeda89008dc77b43228916b4e54bfd1621142349b4ccec8d81cb6b56f0fe1a4ef4a24d3086039eb344b0bf7e4fa8aeaf8a90e4e47c77246e16c254a4a6b6571a49d496538dbe060b83d2c99730d00eedc62029bec9103c34ce015e77ab45141b0160464623a9ad2d2427aa796fae9d36648a1638b6bc1a40e2ce79ade6dcfee320de96bb4a44f3770aa206cc47ed85f28930e0b7ee2278c16f159ef0bcc138ba6a065299ec227d4bf6ed37b43313a22f3126fad06151a0dd686a01855b25ff9961b8712e883292d19a2341f7f7e0deda63502b0e934db7be130cedefb25709d8bab90e9052f7f2665cce91f3cde49767872d7414f4480f531abaaec02eb15405d472a8b8de3ad66281453ebed51712b7ccbfdfd91324e\"}]"
                    }
                ],
                "timestamp": "1631988672987",
                "contractVersion": 1,
                "proofs": [
                    "pIUwSrO53C5D+SQ9LMxztgb+3ihz0Kh3vk1WyH6+s2zBMKE1D6tttEJtqNYDy+MyIWUpdSliD/bHTSEDln4Mcg=="
                ]
            }
        },
        "results": [
            {
                "key": "BLINDSIG_BmFxzLavaz2qhVpkfsXm4j8JqzhmUj5wxVGtvxLf15bi",
                "stringValue": "[{\"userId\":\"NH7VjMULkBhSEEQ+ctm5ARkjl7XTAKKRZ+jV9XAusS0=\",\"maskedSig\":\"aa93cfef25af25ea9fb6db0d1f073600f7d8f622d0b31b44b8fd1ec2921d15aa0ff2e237ef6f9ab76f2d73ae6c06acaca533aa28dde9996c034d5bc61135782c058f67fb2562f6b1b90f02c20a44d19549da2587e8d3e1bc649da39524835cbc76352480c0546ab0a90b11fb2a68326311cec6a92e9513918b8c215c81d5c50f152610e991d5532fda7fc9cc53fd322f2ae270669656da50af5cbef2647a5664b8c69c7d5e3dda1abb2dfc50040a05b80b6586ca6781337ccc1e6139e7269f75c0fd9287d3bf7c6703e64f9b6fd26ec95b05a484c82474280eafda8dec347f7ef7d0c4c90db03e46e38eeda89008dc77b43228916b4e54bfd1621142349b4ccec8d81cb6b56f0fe1a4ef4a24d3086039eb344b0bf7e4fa8aeaf8a90e4e47c77246e16c254a4a6b6571a49d496538dbe060b83d2c99730d00eedc62029bec9103c34ce015e77ab45141b0160464623a9ad2d2427aa796fae9d36648a1638b6bc1a40e2ce79ade6dcfee320de96bb4a44f3770aa206cc47ed85f28930e0b7ee2278c16f159ef0bcc138ba6a065299ec227d4bf6ed37b43313a22f3126fad06151a0dd686a01855b25ff9961b8712e883292d19a2341f7f7e0deda63502b0e934db7be130cedefb25709d8bab90e9052f7f2665cce91f3cde49767872d7414f4480f531abaaec02eb15405d472a8b8de3ad66281453ebed51712b7ccbfdfd91324e\"}]"
            }
        ],
        "resultsHash": "n6kJJcT/5r3CVXYQfD9MDEYVY8btOB35y7Lh+ICH3AE=",
        "timestamp": "1631988675474",
        "proofs": [
            "qYoRnNRMdQOXoznimpzYqpPCvBuPXZkj/UarFckIMhaVtvz9TG9X0vZQqzstd+tK4t9JlDI7Sg8auKCGzbHd5A=="
        ]
    }
}

На этом подготовительную часть для анализа можно считать законченной. В результате имеем две БД по 18 и 33 Гб размером, которые содержат данные о транзакциях которые нам теперь нужно сравнить.

Ведь всё это мы должные проделать для того, чтобы убедиться что данные в блокчейне не были никак подменены.

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

Сравнение исследовательских баз

На этом этапе нам необходимо проверить два факта:

  1. Транзакции записанные в ходе наблюдения идентичны транзакциям в файлах выгрузки на сайте stat

  2. Транзакции скачанные в понедельник с после завершения голосования с нод наблюдения идентичны транзакциям выгрузки на сайте stat

Нам для этого потребуется три базы. Одна база с файлами stat и две других полученные с нод наблюдения шардов блокчейна. Создаем последнюю по аналогии со второй имеем три БД по 18,33 и 33 Гб.

Рассмотрим дампы транзакций из блокчейна

Дамп полученный во время наблюдения

В нем всего 3107873 транзакции. Распределение по типам можно получить так:

SELECT tx.operation_type,COUNT(*) FROM tx
GROUP BY tx.operation_type
ORDER BY tx.operation_type

Тип

Количество

Executed CallContractTransaction addMainKey

1691

Executed CallContractTransaction addVotersList

4775

Executed CallContractTransaction blindSigIssue

1553575

Executed CallContractTransaction commissionDecryption

1672

Executed CallContractTransaction decryption

1672

Executed CallContractTransaction finishVoting

1691

Executed CallContractTransaction removeFromVotersList

48

Executed CallContractTransaction results

1691

Executed CallContractTransaction startVoting

1691

Executed CallContractTransaction vote

1537676

Executed CreateContractTransaction voting-contract

1691

Финальный дамп

Тип

Количество

Executed CallContractTransaction addMainKey

1691

Executed CallContractTransaction addVotersList

4775

Executed CallContractTransaction blindSigIssue

1553575

Executed CallContractTransaction commissionDecryption

1672

Executed CallContractTransaction decryption

1672

Executed CallContractTransaction finishVoting

1691

Executed CallContractTransaction removeFromVotersList

48

Executed CallContractTransaction results

1691

Executed CallContractTransaction startVoting

1691

Executed CallContractTransaction vote

1537676

Executed CreateContractTransaction voting-contract

1691

Распределения аналогичные. Теперь нам нужно сравнить их с сайтом stat, но пока интересное наблюдение. В пятницу в 2021-09-17 15:20 происходила небольшая корректировка списка избирателей (removeFromVotersList). Такие события также видны в блокчейне, поэтому если вдруг кто-то умер, то факт удаления из списка избирателей также будет виден в дампе. В исходном коде смартконтрактов также есть операция по добавлению избирателей, но в голосовании она не использовалась

Сравнивать транзакции в дампах мы будем так:

Транзакции будут равными если у них совпадают временные метки, сигнатуры, внутренний id, входные и выходные параметры.

Для сравнения поделим всё время голосования на 200 временных отрезков и для каждого временного отрезка будем загружать все данные в память и в памяти искать соответствие транзакциям и сравнивать их.

Единственная сложность будет в сравнении входных и выходных параметров, т.к. они в дампе в формате protobuff, а в csv-файлах в json. C# реализация protobuf не позволяет напрямую загрузить json для части сообщения в объект, но поскольку, эти объекты представляют собой по сути обычный словарь - то для них просто сделаем кастомную логика сравнения.

Запустив сравнение можно смело идти смотреть фильм.

Проверка соответствия транзакций
Проверка соответствия транзакций

Это нужно повторить дважды для каждого из дампов.

Полный код сравнения находится в проекте DatabaseComparer в исходном коде

Метрики и графики

Традиционно для систем голосования на базе блокчейна я строю графики зависимости номера блока от времени его добавления (block number/block timestamp), а также производного от него графика времени вычисления блока от номера блока. Эти графики дают представление о стабильности работы блокчейна и дают поводы для размышлений. График зависимости номера блока от времени в случае стабильно работающего private блокчейна должен быть практически прямой наклоненной линией. А график зависимости времени вычисления блока от номера блока должен быть практически прямой горизонтальной линией. Это объясняется тем, что для приватных блокчейнов использующихся в голосованиях в России (с 2019 года я таких наблюдал три: Parity, Exonum и теперь Waves) консенсус настроен таким образом что в среднем каждый новый блок формируется таким образом что события формирования блоков разделяют практически равные интервалы времени. Этот простой факт, например, позволил в 2019 году увидеть проблемы с голосованием в МГД 2019 года.

Поскольку у нас был прямой доступ к нодам наблюдения, помимо информации о транзакциях у нас есть ещё информация о блоках.

Зависимость номера блока от времени
Зависимость номера блока от времени

Самое первое что мы видим: метки времени genesis-блока аж 2021-09-03. Это где-то две недели до голосования. Наверно, в этот момент как раз сформировали рабочие образы системы и подготовили её к дальнейшему развертыванию. Смахнул слезу, когда вспомнил про первый блок биткоина.

Исключим первый блок и выведем график без него

Зависимость номера блока от времени без учета genesis-блока
Зависимость номера блока от времени без учета genesis-блока

Выглядит хорошо. График ровный, для пущей уверенности построим график зависимости времени вычисления блока от его номера.

Время вычисления блока для первого шарда
Время вычисления блока для первого шарда
Остальные шарды

Как видно из графиков среднее время вычисления блока - около 8 секунд.

Теперь построим графики распределения транзакций

Распределение транзакций в блоках
Распределение транзакций в блоках
Распределение транзакций в блоках с привязкой ко времени
Распределение транзакций в блоках с привязкой ко времени
Распределение транзакций по типам для первого шарда
Распределение транзакций по типам для первого шарда
Распределение транзакций по типам для первого шарда с привязкой по времени
Распределение транзакций по типам для первого шарда с привязкой по времени

Тут мы видим три этапа работы системы

  1. Подготовительный - в четверг в 21:00

  2. Само голосование - с 8 утра пятницы до 20 вечера воскресения

  3. Подведение итогов - до 21:25 в воскресение

Описание проектов в репозитории

Analyzer - визуализатор данных

BlockchainVerifier - программа для переноса дампа блокчейна полученного с ноды наблюдателя в исследовательскую БД

DatabaseComparer - утилита для сверки исследовательских БД

EncodingConverter - программа для перевода последовательностей между форматами base64,base58 и hex

StatDownloadVerifier - программа для переноса скачанный файлов с сайта stat.vybory.gov.ru в исследовательскую БД

Voting2021.BlockchainWatcher.Console - тестовый вариант программы для загрузки данных

Voting2021.BlockchainWatcher.Web - программа для загрузки данных из одного шарда блокчейна с ноды наблюдателя

VotingFilesDownloader - программа для скачивания файлов транзакций с официального сайта https://stat.vybory.gov.ru/

Описание файлов данных

Votings.db3 - база в которую загружены все транзакции из csv-файлов

blockchain_dump_3dayend.7z - сырые данные собранные с блокчейна на вечер воскресения

blockchain_dump_3dayend.zip - исследовательская база построенная из данных на вечер воскресения

blockchain_dump_final.7z - сырые данные собранные с блокчейна на утро понедельника

blockchain_dump_final.zip - исследовательская база построенная из данных на утро понедельника

Выводы

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

Обработка всех данных с написанием кода необходимого для этого, потребовала гораздо больше времени

Количество данных (а исходные данные + исследовательские БД в сумме дали почти 122 Гб) уже таково, что в дальнейшем использовать sqlite будет уже нецелесообразно.

Независимо собранные данные совпали с выгрузкой на сайте

В блокчейне отражаются операции удаления умерших избирателей.

С технической точки зрения проблем в работе системы видно не было

Ссылки

Репозиторий с кодом - https://github.com/AlexeiScherbakov/Voting2021

voting.db3 - https://bdsm.ddem.ru/wl/?id=dnBxeMHTAViiuRzqXGTGy34nt9ega29L

blockchain_dump_3dayend.7z - https://bdsm.ddem.ru/wl/?id=ya5cC04NyHxoDeFh4aRbV9bRyVT9impv

blockchain_dump_3dayend.zip - https://bdsm.ddem.ru/wl/?id=uutaBLZiB9SbZXX6yIL1UgBITnSkAS6g

blockchain_dump_final.7z - https://bdsm.ddem.ru/wl/?id=Og22znJ6eDGWIFW5DizBp3C1pfRB5gt6

blockchain_dump_final.zip - https://bdsm.ddem.ru/wl/?id=vE0gRuJ55efL8ku3uvhW0U1P9qn749VY

файлы со stat - https://bdsm.ddem.ru/wl/?id=o2Pepecnim31uUgIEWedyK1DiUBuTOK5

Комментарии (46)


  1. Storm2003
    25.10.2021 22:21
    +3

    Я правильно понимаю, что результатом данного исследование является то, что избирательные участки были открыты с 8:00 до 20:00? Потому, что

    Голоса зашифрованы гомоморфным шифрованием, так что вы можете проверить факт наличия своего голоса, но никто не может узнать как вы проголосовали.

    ни наличие неучтённых голосов, внесённых в процессе ввода данных, ни как введён чей-то голос, проверить невозможно?


    1. alexeishch Автор
      25.10.2021 22:28
      +3

      В процессе работы избиратели не добавлялись, а только удалялись - 2021-09-17 15:20 из списков избирателей были удалены несколько человек. Следовательно неучтенных голосов внесенных в процессе ввода данных нет. Эта статья закрывает тему связанную с техническим наблюдением. Задача технического наблюдения убедиться в том, что система отработала корректно, никакие данные не были изменены в процессе её работы и предоставить возможность верификации факта попадания голоса избирателя. Если хотите я позднее сделаю анализ ещё и по избирателям


      1. Storm2003
        25.10.2021 22:52
        -3

        В процессе работы избиратели не добавлялись, а только удалялись

        В таком случае, либо я не понимаю, что Вы проверяли, либо считалось что-то другое. По данным СМИ, в этом году было выдано рекордное количество открепительных удостоверений(ок. 8 млн). Следовательно, списки избирателей должны были корректироваться в сторону увеличения практически на каждом участке?


        1. alexeishch Автор
          25.10.2021 22:58
          +2

          Причем тут открепительные удостоверения и ДЭГ? Вы не можете по открепительному в ДЭГ голосовать. Открепительное удостоверение это для физических участков, а не для Интернет же. В федеральном ДЭГ было выдано 1553575 бюллетеня. Проголосовало 1537676 человек


          1. Storm2003
            25.10.2021 23:05

            Всё. Понял. Это только Интернет-голосование.


          1. shukshinivan
            26.10.2021 23:40

            Открепительных и сейчас не было. Сейчас уже "мобильный избиратель".


  1. vis_inet
    25.10.2021 22:41
    +3

    Сайт stat устроен таким образом, что парсером html страниц его стащить было невозможно

    Скажите, а зачем было именно так сделано?


    1. alexeishch Автор
      25.10.2021 22:44
      -1

      JavaScript сейчас суют везде просто. Даже там где без него можно обойтись. Но в этом случае для меня даже всё оказалось проще, вместо парсинга страниц сайта, я написал http-клиент, который просто дергал их API. Это работало в итоге быстрее чем парсер страниц


  1. webdi
    25.10.2021 23:05

    Ух сколько труда. А такое вообще можно в общий доступ? Вам там ничего не сделают?)


    1. Atreides07
      25.10.2021 23:37
      +6

      Можете не переживать за автора. Ведь статья (которая появилась столько времени спустя после голосования, что уже странно) всего лишь подтверждает, что технически все работало, а не то что были странные аномалии в голосах. Т.е. статья полностью нейтральная и соответствует риторике властей и Венедиктова, что техническая группа не нашла проблем, а не то, что не было аномалий с перегослованиями и т.д. и т.п., так что автору ничего не грозит :)


      1. alexeishch Автор
        25.10.2021 23:44
        +6

        Венедиктов про московскую систему же говорил. А я писал про федеральную. Сейчас есть две разные системы электронного голосования. Московскую я пока смотрел только краем глаза, но обязательно и с ней разберусь


  1. Peterlos
    26.10.2021 03:59

    Отлично, хоть ктото пишет про использование технологий в политике


  1. Pavel1114
    26.10.2021 05:06
    +4

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


    1. norguhtar
      26.10.2021 09:00

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


      1. Pavel1114
        26.10.2021 09:05
        -1

        1. Это устройство действительно может содержать(и вполне возможно содержит) какие то закладки, backdoor и прочее. И, если бы рынок ПК был монопольным или, ещё хуже, полностью подконтрольным государству, то я бы не сомневался в их наличии.
        2. Компьютер практически нельзя собрать самому, поэтому приходится в известной мере доверять профессионалам. Голосование уже тысячи лет проводят без ДЭГ и внедрение этой непрозрачности вовсе необязательно.


        1. norguhtar
          26.10.2021 09:15
          +2

          Эмм рынок ПК практически монополен. Процессоры x86 делает две фирмы и они американские.

          поэтому приходится в известной мере доверять профессионалам.

          К этому я и клонил. Вы почему-то в случае ПК доверяете, а в случае ДЭГ нет.

          Голосование уже тысячи лет проводят без ДЭГ и внедрение этой непрозрачности вовсе необязательно.

          До компьютеров все считали на счетах, внедрение компьютеров вовсе не обязательно. Это звучит именно так.

          Мне просто не очень понятно почему люди топят за бумажное голосование. У вас или есть подтасовки при голосовании или их нет. Если они есть бумажное у вас голосование или ДЭГ не очень важно.

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


          1. Pavel1114
            26.10.2021 09:18
            -1

            До компьютеров все считали на счетах, внедрение компьютеров вовсе не обязательно. Это звучит именно так.
            Абсурдно объяснять, но на компьютерах не только считают, поэтому аналогия не верна.
            К примеру к вбросу мертвых душ в списки голосования уязвимы обе системы.
            В ДЭГ даже этого делать не надо. Это как сравнивать хромую лощадь и камень. Да, лощадь вряд-ли станет чемпионом на скачках, но в сравнении с камнем, у неё невероятно больше шансов.


            1. norguhtar
              26.10.2021 09:21

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


              1. Pavel1114
                26.10.2021 09:24
                +1

                Нет. Не важно как он складывает единицы и нули. Важно как мы с ним взаимодействуем — и в этом счёты не могут заменить компьютер. А обычное голосование легко заменяет ДЭГ. Поэтому аналогия не верна.


                1. norguhtar
                  26.10.2021 09:28
                  +2

                  Не важно как он складывает единицы и нули. Важно как мы с ним взаимодействуем — и в этом счёты не могут заменить компьютер.

                  Могут, просто это будет очень долго :) Есть даже комикс про это.

                  А обычное голосование легко заменяет ДЭГ.

                  Как бы вообще-то происходит наоборот ДЭГ заменяет обычное голосование. И кстати перевод на ДЭГ если конечно ему все доверяют позволяет хорошо так сэкономить бюджетные средства.


                  1. Pavel1114
                    26.10.2021 09:31
                    -1

                    Могут, просто это будет очень долго :) Есть даже комикс про это.
                    как на счётах, к примеру, можно отрендерить сайт. Пусть даже за неограниченное время. Хотя это уже совсем абсурд
                    Как бы вообще-то происходит наоборот ДЭГ заменяет обычное голосование. И кстати перевод на ДЭГ если конечно ему все доверяют позволяет хорошо так сэкономить бюджетные средства.

                    Так никто и не доверяет. И, как я и указал в первом комментарии, большинство и не может доверять так как не понимает что там вообще происходит.


                    1. norguhtar
                      26.10.2021 09:44
                      +1

                      как на счётах, к примеру, можно отрендерить сайт. Пусть даже за неограниченное время. Хотя это уже совсем абсурд

                      Узнайте что такое машина тьюринга :) При рендере сайта у вас процессор просто берет из одного места байты и шлет их в другое. И то что то устройство куда он эти байты отправил нарисовало картинку и вы увидели ее это другое дело.

                      Так никто и не доверяет. И, как я и указал в первом комментарии, большинство и не может доверять так как не понимает что там вообще происходит.

                      Я с таким же успехом могу не доверять бумажном голосованию. Как использование бумажного голосования повышает доверие? Я могу к примеру проверить учтен ли мой голос? А правильно ли учтен мой голос? А не забракован ли мой бюллетень?

                      Даже если я стану наблюдателем я не смогу это проверить. Я могу только как-то там убедиться что процесс голосования и подсчета голосов не нарушается и все.

                      А в случае ДЭГ я могу проверить учтен ли голос и правильно ли учтен. В текущий момент проблема больше в наличии инструментов, чтобы это мог сделать каждый.


                      1. Pavel1114
                        26.10.2021 09:47
                        -1

                        Узнайте что такое машина тьюринга :) При рендере сайта у вас процессор просто берет из одного места байты и шлет их в другое.
                        я же вроде вам уже указал что не важно как компьютер складывает там байты, я им пользуюсь не для этого. Счёты не могут заменить компьютер. Не понимаю с чем вы спорите.


                      1. norguhtar
                        26.10.2021 09:54
                        +1

                        Я вам намекаю, что ДЭГ дает больше возможностей чем бумажное голосование. В том числе оно дает возможность провести независимый аудит. Что в данном случае и делается. В итоге затрачивая меньше денег, мы получаем более прозрачную систему.

                        При ДЭГ нам не нужны ни прозрачные урны, ни 100500 камер ни такое количество участков и такое количество наблюдателей на каждом участке.

                        А вопрос о доверии это вопрос о доверии к выборам в целом. И его в России нет. А какие они там бумажные или ДЭГ мало важно.

                        Разница между ДЭГ и бумажным голосованием ровно такая же. Как между компьютером и счетами.


                      1. Pavel1114
                        26.10.2021 09:58
                        -3

                        А я вам намекаю на то что ещё не придумали прозрачной схемы ДЭГ. Допускаю что когда нибудь придумают, если захотят. В текущей реализации это просто чёрный ящик. Да они дают какой то массив информации, но из него невозможно сделать каких либо выводов или что то проверить. России ооочень далеко до того доверия к власти, чтобы внедрять ДЭГ.


                      1. norguhtar
                        26.10.2021 10:12
                        +3

                        А я вам намекаю на то что ещё не придумали прозрачной схемы ДЭГ. Допускаю что когда нибудь придумают, если захотят. В текущей реализации это просто чёрный ящик.

                        А бумажная система сейчас прозрачная? Для меня нет. Знаете почему? Да потому что она не дает никаких данных вообще. Мне говорят сдай бюллетень туда, потом что-то там происходит мне объявляют результаты. Очень прозрачно.

                        Более того мне не понятно как использование бумажной системы хоть от чего-то защищает. Это вот прям аргументы вида как бухгалтерам компьютеры когда внедряли там тоже было

                        Да ваш компьютер фигню насчитает! Толи дело я на счетах

                        Тоже самое происходит и с ДЭГ

                        России ооочень далеко до того доверия к власти, чтобы внедрять ДЭГ.

                        Я еще раз задам вопрос. А к бумажным выборам доверие есть? Я вот не замечал. А ДЭГ позволит как раз повысить доверие к выборам. Я понимаю почему многие противятся это ваши компухтеры криптография и гомогенное шифрование! Но это дело времени.


                      1. Pavel1114
                        26.10.2021 10:17
                        -1

                        эх


          1. alexeishch Автор
            26.10.2021 09:22
            +1

            На счёт мертвых душ. Для этого требуется заведение "мертвой души " в ГосУслугах, у аккаунта должен быть действующий СНИЛС и ИНН. Налоговая за такое вставит любому региональному руководителю. Как отличить в информационной системе "мертвую душу" от уклониста от налогов?
            Я вот тут вижу скорее проблемы с несанкционированным доступом к аккаунтам в ГосУслугах.


            1. norguhtar
              26.10.2021 09:25
              +2

              Ну вы же понимаете, что я могу на стороне госуслуг дописать отдельный модуль который будет ходить когда надо в базу мертвых душ? В фактической базе их не будет, а там будут.

              Я вот тут вижу скорее проблемы с несанкционированным доступом к аккаунтам в ГосУслугах.

              Это да. Как и заведение аккаунта для тех кто ими никогда не пользовался и использование его для голосования.


          1. vis_inet
            26.10.2021 14:37
            +1

            Мне просто не очень понятно почему люди топят за бумажное голосование

            Потому, что его хотя бы можно проверить путём сверки итогов по протоколам.

            Правда, при отсутствии противодействия заинтересованных в манипуляциях лиц.


            1. norguhtar
              26.10.2021 14:39

              И толку? Вы не можете верифицировать итоги. Ну никак. В электронном можно.


              1. vis_inet
                26.10.2021 18:39

                Почему?

                Наблюдатели присутствуют при подсчете, затем при оформлении итогового протокола на каждом участке.

                После этого им остаётся собрать протоколы всех участков и вывести общий итог по городу (субъекту).

                Итог сравнивается с данными избиркома.

                В случае расхождений - обращаются с жалобами в ЦИК и в суд.


                1. norguhtar
                  26.10.2021 18:41

                  Ну для начала потому что я не могу проверить лично свой голос. Если наблюдатель просмотрел или зазевался или в сговоре, то все. У нас нет прозрачной истории которую можно посмотреть потом.


    1. Chuvi
      27.10.2021 07:16

      Нет, это значит что подавляющему большинству требуется получение новых знаний.

      Напомню что 100 лет назад не все умели писать и читать.


    1. vlad_gor
      27.10.2021 15:40

      Бумажное голосование фальсифицировать проще чем электронное


      1. vis_inet
        27.10.2021 19:44

        Почему?


        1. alexeishch Автор
          28.10.2021 02:00

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


          1. vis_inet
            28.10.2021 06:21

            Вы не можете просто так вбросить бюллетени

            Про последние выборы читал несколько статей в которых описывалось, что это было.


  1. indium_antimonide
    26.10.2021 09:58
    +8

    Я думаю, что в самом начале статьи надо было уточнить, что Москве и по России использовались две разные системы дистанционного голосования, которые выполнили разные подрядчики.


  1. Antibunny
    26.10.2021 12:35
    +4

    Добрый день, хочу сказать спасибо от команды разработчиков Waves Enterprise за хорошую, техническую статью. Приятно когда на твою работу смотрят профессионально, а не через призму "наши деды и без этого хорошо жили"! ))

    Если у вас есть какие-то вопросы по внутреннему устройству системы (хотя Вы и самостоятельно копнули достаточно глубоко), будем рады на них ответить!

    з.ы. И да, система "Ростелеком-Waves" и система ДИТ Москвы - совершенно разные вещи ) Мы работаем над федеральным ДЭГ и к московским выборам отношения не имеем.


  1. shukshinivan
    26.10.2021 23:37

    Массивный труд, конечно, спасибо. Но. Дочитал до конца и поймал себя на мысли, что как будто бы я прочитал описание методов, которые будут применяться, но пропустил описание собственно исследование.

    Цель статьи - показать, как наблюдать за системой ДЭГ? А как же в данных найти что-то интересное? А то ведь смысл наблюдения за такими системами в том, чтобы или подтвердить, что всё ок, или показать, что что-то далеко не ок. И этого смысла что-то я не нашёл :(


    1. alexeishch Автор
      27.10.2021 00:46

      Да, цель статьи именно в том, как наблюдать за ДЭГ. Система реализована по принципу "двух агентств", здесь речь шла о том, как наблюдать за происходящем во втором. Тут показано, как обрабатывать эти данные, как находить события на примере. Однако в текущем голосовании использовались не все функции системы. Например, было удаление умерших избирателей, но не было добавления новых. К сожалению, не покажешь того чего нет в данных
      Если вы посмотрите предыдущие статьи, которые я писал, то там вы увидите на примере Московской системы, как технические метрики позволяют найти проблемы. Любое такое исследование по сути уникально, т.к. каждый запуск любой из систем всегда приносит что-то новое. Например, если вы возьмете и построите графики block timestamp и block time для текущей Московской системы, то вы увидите то, что не увидели ни Брюханова, ни техническая группа Венедиктова - а этот метод я описал еще в бородатом 2019 году )
      Соответственно на основании этой метрики мы можем судить о наличии проблем непосредственно блокчейна. По наличию определенных транзакций мы можем видеть операции добавление и удаление избирателей аналогичные вычеркиваниям или вписываниям в книгу избирателей непосредственно во время голосования. Но я не могу показать обнаружение таких событий на примере банально в следствие отсутствия таких событий.


      1. shukshinivan
        27.10.2021 01:50
        +2

        Я один из адресатов статьи, наблюдатель с многолетним опытом. И я именно что наблюдения за голосованием не увидел, хотя оно вынесено в название статьи. Наблюдение в России - это всегда активный поиск проблем или доказательство, что их нет, поскольку федеральные выборы у нас - это всегда (вообще всегда) история фальсификаций. Наблюдение пассивное, где не поставлена проблематика доверия результатам - это не наблюдение. Каждый наблюдатель на участке именно это и держит в голове, хочет понять, его уже обманули или ещё нет. Вы как будто этот момент исключили из рассмотрения.

        Вы один из немногих, кто имел доступ к ноде (Вы в ДИТ работаете?). Поэтому я ожидал увидеть именно решение проблематики, поставленной ранее публикациями о ДЭГ от Гонгальского, Жижина и прочих, где выявлены очень серьёзные факторы недоверия как архитектурно, так и в данных.

        Вывод, что в список избирателей никого не добавили в день голосования - извините, очень слабый в контексте проблематики, потому что в этом моменте и не подозревали жульничества. Я не хочу принизить работу, которая явно проделана большая, надеюсь, Ваши наработки помогут на следующих выборах разоблачить жуликов.


        1. alexeishch Автор
          27.10.2021 11:02

          Причем тут ДИТ? Это федеральная система, не московская. Я выше давал комментарий, что с московской я не разбирался


          1. shukshinivan
            27.10.2021 15:21
            -1

            Да первое, что пришло в голову, потому что первый же вопрос после чтения статьи - понять, почему проблематика отсутствует. Каких мы все знаем программистов при власти? Ну, ДИТ. Например, часть сотрудников московским ДЭГ занялись, а кто-то был на наблюдение за федералами пущен. Не всем же ДИТом прогать ДЭГ, кого-то и наблюдать можно пусить.

            Но интересно, что Вы решили возразить лишь на второстепенный вопрос в скобках.


            1. alexeishch Автор
              27.10.2021 17:09
              +1

              Очевидно потому что вы задали только один вопрос. Помимо этого в заговоке вынесено, что система Ростелеком-Waves. В статье написано что доступ одобрялся Ростелекомом, приходили рассказывали как работает сотрудники Waves но при этом вы пишете странные вещи. Я к сожалению никак не могу угадать ход вашей мысли :-(
              В 2019 году я смог показать что в ДИТ в голосовании в МГД блокчейн не работал треть времени. Здесь я также построили аналогичные метрики, которые показывали на стабильность работы этого компонента. Также я независимо записывал данные и сохранял к себе, перепроверив это я пришел к выводу что в системе данные никак не подменялись. Каждая операция в блокчейне записана. Списки избирателей были сформированы в четверг вечером, и в пятницу днем из них были вычеркнуты несколько человек. Цель технического наблюдения в том, чтобы убедиться в корректности работы системы, отсутствии проблем и неизменности данных в блокчейне.