Известная история является одним из Fortran, который вызвал спутник аварию (Mariner Венеры) из-за «-» за ошибки «~» ... Эта история в C ++ и о недостающем '&», И как спутниковая история также начинается с грохотом.
У меня был свой настроенный сервер Bitcoin (на основе libcoin), работающих на различных макинтош и окон рабочего стола машины, работающие в течение нескольких недель без каких-либо проблем, она выжила реорганизаций и изменения протокола на основе недавних (BIP0016 / BIP0030) тихо, и, казалось, довольно стабильным. Я, следовательно, установил его в своей производственной среде машину Ubuntu в Linode. Оно составлено и функционировало несколько раз, прежде чем на Linux, за исключением того, что иногда работает на небольших виртуальных машинах, которые я видел сбои из-за проблемы с памятью. Ничто не будет действительно встревожен, и экземпляр работает на амазонки большой инстанции никогда не разбился. Я поэтому компилируется в код и начал его на Linode. Blockchain скачать ... переустройство и аварии! Причина была bad_alloc, поэтому, скорее всего, проблема памяти и Afterall экземпляра Linode была только 1gig оперативной памяти. В моем пользовательском сервере я также сохранить некоторые довольно большие структуры данных в памяти, поэтому я отключил их во время загрузки цепи и попытался снова. Реорганизовать, и аварии! Опять же из-за bad_alloc.
Досадно, после аварии базы данных испортились, а также. Я до сих пор считал, что сбои были вызваны низкой память, но я хотел, чтобы убедиться, что в будущем я мог бы по крайней мере восстановить грациозно из искаженной базы данных. Так что я попытался выяснить, в каком состоянии база данных была оставлена в.
В методе реорганизовать класс BlockChain (в основном аналогичен методе реорганизовать в Bitcoin / Bitcoin) Есть много хороших тесты, чтобы проверить, если все терпит неудачу - если блоки не могут быть считаны с диска или если отключить не удается. Если это так серия накопленных транзакций базы данных прерываются (TxnAbort), оставляя базу данных в том же состоянии, как и прежде, и обеспечение того, чтобы даже мысль о реорганизации не удалось (и не сможет снова) база данных остается в том же состоянии, а та же ошибка будет появляться при перезагрузке и поэтому может быть легко отлаживается.
В моем случае это было исключение памяти выброшен в цикле, где все txes выталкивается на стеке, чтобы воскреснуть после реорганизации цепи. Исключение перехватывается, но это не зацепила, прежде чем в способе обработки сообщений (ProcessMessage в Bitcoin, handleMessage в libcoin). Вот это приводит к появлению сообщения об ошибке, но программа продолжает и транзакции базы данных никогда не прерываются (TxnAbort). Неудавшаяся Реорганизовать повторит его самостоятельно, а журнал транзакций базы данных заполняется до 500 незавершенных транзакций, а затем BDB делает выход из программы. Однако, в какой-то момент между ними, по крайней мере, в моем коде, лучшая высота сиделось в базе данных, и что привело к коррупции.
Я исправил проблему, вставив попробовать поймать вокруг все в реорганизовать до TxnAbort в обеспечении правильного поведения даже в случае исключения памяти.
Вместо восстановления базы данных (с нулем загрузки) Я попытался восстановить базу данных: Принуждение Реорганизовать 10 шагов назад и уборку blockchainindex для всех не основных цепи блоков. Однако, это сразу же вызвало очередную аварию реорганизовать из-за bad_alloc! На этот раз причина была явно не подано до памяти. Я отлажена код и тот же цикл, как и раньше был виновником:
Код:
// Операции памяти очереди воскресить
BOOST_FOREACH (Const сделка& TX, block.getTransactions ())
если (! tx.isCoinBase ()) {
vResurrect.push_back (ТХ);
}
Блок :: getTransactions () был определен как:BOOST_FOREACH (Const сделка& TX, block.getTransactions ())
если (! tx.isCoinBase ()) {
vResurrect.push_back (ТХ);
}
Код:
Const TransactionList getTransactions () {константные возврата _transactions; }
libcoin инкапсулирует все классы, и, следовательно, цикл над (константной версией) сделки в блоке делается таким образом. У меня есть другая часть кода (в блоке), где:Код:
BOOST_FOREACH (Const сделка& ТХ, _transactions)
// сделать что-то с ТМ
// сделать что-то с ТМ
вызываются несколько раз без проблем, но код разбился там, и это было ТМ, который был поврежден! Я изменил цикл на нормальный для block.getNumTransactions цикла с использованием () и block.getTransaction (INT) - теперь код бежал отлично до блока 171091 - которые каждый bitcoinerd будет признавать в качестве первого блока 15 марта! BIP0030 ... Мой BIP0030 код:
Код:
если (pindex->NTime > _chain.timeStamp (Chain :: BIP0030))
BOOST_FOREACH (Const сделка& TX, block.getTransactions ()) {
TxIndex txindexOld;
если (ReadTxIndex (tx.getHash (), txindexOld))
BOOST_FOREACH (константные DiskTxPos &поз, txindexOld.getSpents ())
если (pos.isNull ())
вернуться ложным;
}
Эй, опять петля BOOST_FOREACH! Эта конструкция была, по-видимому каким-то образом загрязняется - это Google для «BOOST_FOREACH константной ссылке» дал это как:BOOST_FOREACH (Const сделка& TX, block.getTransactions ()) {
TxIndex txindexOld;
если (ReadTxIndex (tx.getHash (), txindexOld))
BOOST_FOREACH (константные DiskTxPos &поз, txindexOld.getSpents ())
если (pos.isNull ())
вернуться ложным;
}
http://www.richelbilderbeek.nl/CppBOOST_FOREACHExample1.htm
Обратите внимание на стр RICHEL в:
Код:
// ПЛОХО: Собирает и сбой программы
// станд :: засорить << __func__ << '\ П'; BOOST_FOREACH (Const станд :: строка& S, F ()) {T + = с; }
Таким образом, вы не можете использовать функцию, возвращающую копию вектора в BOOST_FOREACH, однако константная ссылка на него работает, но будет изрыгать предупреждение компилятора. Изменение Блок :: getTransactions (), чтобы:// станд :: засорить << __func__ << '\ П'; BOOST_FOREACH (Const станд :: строка& S, F ()) {T + = с; }
Код:
Const TransactionList& getTransactions () Const {возврата _transactions; }
// ^ отметить единственный &
сделал все работает гладко снова. Таким образом, преступник был отсутствующий "&'Или более правильно, что BOOST_FOREACH, которые не ведут себя правильно. Тем не менее, он ведет себя правильно при компиляции на визуальной студии и Xcode. Поэтому я никогда не видел эту ошибку раньше ...// ^ отметить единственный &
Какой урок тогда? Я думаю, что есть два:
* Используйте либо исключения или ложные / истинные функции в программе не так! Somethimes лучше врезаться, чем продолжать пытаться.
* Используйте макросы (BOOST_FOREACH) с большой осторожностью, поведение часто трудно предсказать, и также трудно отлаживать. Я буду над изменением времени всех BOOST_FOREACH в libcoin к нормальной для / в то время как петли.
Спасибо за чтение этого - я надеюсь, что вы нашли его полезным!
Ура,
Майкл