gorus5 (OP)
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 02, 2018, 11:51:00 AM Last edit: April 02, 2018, 01:29:40 PM by gorus5 |
|
Я клонирую альткойн. Все работает отлично. За исключеним самого главного - не генерируются PoS блоки. Есть несколько клиентов, они соеденены, значок Staking светится (хотя всегда пишет network weight - 0). На обычном PoW майнинге все работает как надо, но моя цель в конечном итоге перевести валюту только на PoS, а он не работает. Когда майнинг выключен, новые блоки не генерируются и соответсвенно транзации не проходят. Пошарив код и дебаг логи, обнаружил что блоки генерируются. НО не принимаются, т.к. они имеют некорректную структуру. А именно не проходит последнее условие в проверке isCoinStake bool IsCoinStake() const { // the coin stake transaction is marked with the first output empty return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty()); } То есть, как видно из комментария и условия, для валидной транзакции нулевой vout должен быть пустым. У меня же, по каким-то причинам, на этом месте стоит сама транзакция перевода монет. Вот пример блока, который пытается сгенерироваться (проблема там, где 52 строчка кода - https://pastebin.com/M7xh9Bt0) { "hash":"af19fb5ce7a8f8b5c1ff4a71e781f3815301065a7a01264e05dacf8bdd15ecc1", "confirmations":-1, "size":378, "version":1, "merkleroot":"0000000000000000000000000000000000000000000000000000000000000000", "time":1522419811, "nonce":0, "bits":"1e0fffff", "tx":[ { "txid":"5e069b3266173804322a8cff18ddc9e199e9886948f5374ecb4d32387458dadf", "version":1, "time":1522419811, "locktime":0, "vin":[ { "coinbase":"028200", "sequence":4294967295 } ], "vout":[ { "value":0.00000000, "n":0, "scriptPubKey":{ "asm":"", "hex":"", "type":"nonstandard" } } ] }, { "txid":"9a070cac3b9cc72e9800c85cf171b38f758fb510af5e87f7481e2f30be85643b", "version":1, "time":1522419786, "locktime":76, "vin":[ { "txid":"b32118915e6da3b8c15b03900b422b40f6f7a7b6e41ab5e62b1553aa7fe8e7a6", "vout":0, "scriptSig":{ "asm":"30440220334c507ef89db58cc9636be1aad6f83670fd1274b66f8266528791c53a000196022038869d9b4d825b6a27009e836a03dea0857afa02b156126fb01c4bcf3250167201 02115f9d6a68fa6811bb11dec153930b93b59e9f4304475d66358ca1a17150989f", "hex":"4730440220334c507ef89db58cc9636be1aad6f83670fd1274b66f8266528791c53a000196022038869d9b4d825b6a27009e836a03dea0857afa02b156126fb01c4bcf32501672012102115f9d6a68fa6811bb11dec153930b93b59e9f4304475d66358ca1a17150989f" }, "sequence":4294967294 } ], "vout":[ { "value":99996997.99950001, "n":0, "scriptPubKey":{ "asm":"OP_DUP OP_HASH160 5297cc5e2ef14653ec94f3b8496efd31dc2408b7 OP_EQUALVERIFY OP_CHECKSIG", "hex":"76a9145297cc5e2ef14653ec94f3b8496efd31dc2408b788ac", "reqSigs":1, "type":"pubkeyhash", "addresses":[ "BBynsaS3XdgJhhXwfy68r1rfnK18FHQuXZ" ] } }, { "value":1.00000000, "n":1, "scriptPubKey":{ "asm":"OP_DUP OP_HASH160 0aadf7a989f4a49e81c42a5111866a384b759b49 OP_EQUALVERIFY OP_CHECKSIG", "hex":"76a9140aadf7a989f4a49e81c42a5111866a384b759b4988ac", "reqSigs":1, "type":"pubkeyhash", "addresses":[ "B5RYn6v57b4rKkv9JNgUBEJj3aVhM2xnDX" ] } } ] } ] } И там нету нулевого vout в первой транзации (именно в первой, т.е. по порядку - второй). Никак не могу понять в чем причина. Я в коде ничего не менял что имело бы отношение к этому.
|
|
|
|
Cripto_Developer
Newbie
Offline
Activity: 10
Merit: 0
|
|
April 02, 2018, 12:05:59 PM |
|
Я клонирую альткойн. Все работает отлично. За исключеним самого главного - не генерируются PoS блоки.
Можно узнать какой альткоин Вы клонируете? Советую посмотреть начались ли PoS блоки в том альткоине, который Вы клонируете. Если это баг не Ваш, то скорее всего его решит команда, чей код Вы берете за исходный.
|
|
|
|
gorus5 (OP)
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 02, 2018, 12:17:12 PM |
|
Я клонирую альткойн. Все работает отлично. За исключеним самого главного - не генерируются PoS блоки.
Можно узнать какой альткоин Вы клонируете? Советую посмотреть начались ли PoS блоки в том альткоине, который Вы клонируете. Если это баг не Ваш, то скорее всего его решит команда, чей код Вы берете за исходный. BlackCoin. Да, там есть PoS, он уже давно только на нем и работает.
|
|
|
|
Cripto_Developer
Newbie
Offline
Activity: 10
Merit: 0
|
|
April 02, 2018, 12:49:12 PM |
|
|
|
|
|
gorus5 (OP)
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 02, 2018, 01:13:45 PM |
|
|
|
|
|
Cripto_Developer
Newbie
Offline
Activity: 10
Merit: 0
|
|
April 02, 2018, 01:19:01 PM |
|
Уточните еще один момент. С какой высоты начинаются PoS блоки?
|
|
|
|
gorus5 (OP)
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 02, 2018, 01:22:43 PM |
|
Уточните еще один момент. С какой высоты начинаются PoS блоки?
В блэккойне стоит значение 10000. Я пробовал и ставить маленькое (100) и оставлять как есть - результат тот же. Если высота блоков не достигла значения nLastPOWBlock, это ведь не значит что PoS не может работать? Просто до того времени может быть как PoW так и PoS, а когда высота станет больше, будут приниматься только PoS.
|
|
|
|
Cripto_Developer
Newbie
Offline
Activity: 10
Merit: 0
|
|
April 02, 2018, 01:25:42 PM |
|
Уточните еще один момент. С какой высоты начинаются PoS блоки?
Я пробовал и ставить маленькое (100) и оставлять как есть - результат тот же. Если высота блоков не достигла значения nLastPOWBlock, это ведь не значит что PoS не может работать? Просто до того времени может быть как PoW так и PoS, а когда высота станет больше, будут приниматься только PoS. Интересно Сколько блоков для подтверждения... ?
|
|
|
|
gorus5 (OP)
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 02, 2018, 01:29:11 PM |
|
Уточните еще один момент. С какой высоты начинаются PoS блоки?
Я пробовал и ставить маленькое (100) и оставлять как есть - результат тот же. Если высота блоков не достигла значения nLastPOWBlock, это ведь не значит что PoS не может работать? Просто до того времени может быть как PoW так и PoS, а когда высота станет больше, будут приниматься только PoS. Интересно Сколько блоков для подтверждения... ? Поставил nCoinbaseMaturity = nStakeMinConfirmations = 10.
|
|
|
|
Cripto_Developer
Newbie
Offline
Activity: 10
Merit: 0
|
|
April 02, 2018, 01:36:47 PM |
|
Если высота блоков не достигла значения nLastPOWBlock, это ведь не значит что PoS не может работать?
PoS не будет работать если нет созревших монет. Буду копать инфу по данной ошибке, по итогам отпишусь. Может кто-то из форумчан встречался с этой проблемой и ответит Вам. Удачи!
|
|
|
|
gorus5 (OP)
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 02, 2018, 02:06:54 PM |
|
Если высота блоков не достигла значения nLastPOWBlock, это ведь не значит что PoS не может работать?
PoS не будет работать если нет созревших монет. Буду копать инфу по данной ошибке, по итогам отпишусь. Может кто-то из форумчан встречался с этой проблемой и ответит Вам. Удачи! Я знаю что не будет работать. Но монеты есть, и staking горит. Ок, спасибо за помощь)
|
|
|
|
Cripto_Developer
Newbie
Offline
Activity: 10
Merit: 0
|
|
April 02, 2018, 09:29:28 PM |
|
Я знаю что не будет работать. Но монеты есть, и staking горит. Ок, спасибо за помощь)
Кстати, с какого возраста монеты начинают майнить? Вы этот вопрос изучили?
|
|
|
|
gorus5 (OP)
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 03, 2018, 06:45:06 AM |
|
Я знаю что не будет работать. Но монеты есть, и staking горит. Ок, спасибо за помощь)
Кстати, с какого возраста монеты начинают майнить? Вы этот вопрос изучили? В оригинальном коде стоит 8 часов минимум, но я ставил меньше для теста.
|
|
|
|
gorus5 (OP)
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 03, 2018, 07:02:22 AM |
|
Выяснил следующее - CoinStake транзация пытается сгенерироваться в методе wallet.cpp/CreateCoinStake как и положено. bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, int64_t nFees, CTransaction& txNew, CKey& key) { CBlockIndex* pindexPrev = pindexBest; CBigNum bnTargetPerCoinDay; bnTargetPerCoinDay.SetCompact(nBits);
txNew.vin.clear(); txNew.vout.clear();
// Mark coin stake transaction CScript scriptEmpty; scriptEmpty.clear(); txNew.vout.push_back(CTxOut(0, scriptEmpty));
// Choose coins to use int64_t nBalance = GetBalance();
if (nBalance <= nReserveBalance) return false;
vector<const CWalletTx*> vwtxPrev;
set<pair<const CWalletTx*,unsigned int> > setCoins; int64_t nValueIn = 0;
// Select coins with suitable depth if (!SelectCoinsForStaking(nBalance - nReserveBalance, setCoins, nValueIn)) return false; if (setCoins.empty()) return false;
int64_t nCredit = 0; CScript scriptPubKeyKernel; CTxDB txdb("r"); BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { static int nMaxStakeSearchInterval = 60; bool fKernelFound = false; for (unsigned int n=0; n<min(nSearchInterval,(int64_t)nMaxStakeSearchInterval) && !fKernelFound && pindexPrev == pindexBest; n++) { boost::this_thread::interruption_point(); // Search backward in time from the given txNew timestamp // Search nSearchInterval seconds back up to nMaxStakeSearchInterval COutPoint prevoutStake = COutPoint(pcoin.first->GetHash(), pcoin.second); int64_t nBlockTime; if (CheckKernel(pindexPrev, nBits, txNew.nTime - n, prevoutStake, &nBlockTime)) { // Found a kernel LogPrint("coinstake", "CreateCoinStake : kernel found\n"); vector<valtype> vSolutions; txnouttype whichType; CScript scriptPubKeyOut; scriptPubKeyKernel = pcoin.first->vout[pcoin.second].scriptPubKey; if (!Solver(scriptPubKeyKernel, whichType, vSolutions)) { LogPrint("coinstake", "CreateCoinStake : failed to parse kernel\n"); break; } LogPrint("coinstake", "CreateCoinStake : parsed kernel type=%d\n", whichType); if (whichType != TX_PUBKEY && whichType != TX_PUBKEYHASH) { LogPrint("coinstake", "CreateCoinStake : no support for kernel type=%d\n", whichType); break; // only support pay to public key and pay to address } if (whichType == TX_PUBKEYHASH) // pay to address type { // convert to pay to public key type if (!keystore.GetKey(uint160(vSolutions[0]), key)) { LogPrint("coinstake", "CreateCoinStake : failed to get key for kernel type=%d\n", whichType); break; // unable to find corresponding public key } scriptPubKeyOut << key.GetPubKey() << OP_CHECKSIG; } if (whichType == TX_PUBKEY) { valtype& vchPubKey = vSolutions[0]; if (!keystore.GetKey(Hash160(vchPubKey), key)) { LogPrint("coinstake", "CreateCoinStake : failed to get key for kernel type=%d\n", whichType); break; // unable to find corresponding public key }
if (key.GetPubKey() != vchPubKey) { LogPrint("coinstake", "CreateCoinStake : invalid key for kernel type=%d\n", whichType); break; // keys mismatch }
scriptPubKeyOut = scriptPubKeyKernel; }
txNew.nTime -= n; txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second)); nCredit += pcoin.first->vout[pcoin.second].nValue; vwtxPrev.push_back(pcoin.first); txNew.vout.push_back(CTxOut(0, scriptPubKeyOut));
LogPrint("coinstake", "CreateCoinStake : added kernel type=%d\n", whichType); fKernelFound = true; break; } }
if (fKernelFound) break; // if kernel is found stop searching }
if (nCredit == 0 || nCredit > nBalance - nReserveBalance) return false;
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { // Attempt to add more inputs // Only add coins of the same key/address as kernel if (txNew.vout.size() == 2 && ((pcoin.first->vout[pcoin.second].scriptPubKey == scriptPubKeyKernel || pcoin.first->vout[pcoin.second].scriptPubKey == txNew.vout[1].scriptPubKey)) && pcoin.first->GetHash() != txNew.vin[0].prevout.hash) { // Stop adding more inputs if already too many inputs if (txNew.vin.size() >= 10) break; // Stop adding inputs if reached reserve limit if (nCredit + pcoin.first->vout[pcoin.second].nValue > nBalance - nReserveBalance) break; // Do not add additional significant input if (pcoin.first->vout[pcoin.second].nValue >= GetStakeCombineThreshold()) continue;
txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second)); nCredit += pcoin.first->vout[pcoin.second].nValue; vwtxPrev.push_back(pcoin.first); } }
// Calculate reward { int64_t nReward = GetProofOfStakeReward(pindexPrev, 0, nFees); if (nReward <= 0) return false; LogPrintf("nReward <= 0\n");
nCredit += nReward; }
if (nCredit >= GetStakeSplitThreshold()) txNew.vout.push_back(CTxOut(0, txNew.vout[1].scriptPubKey)); //split stake
// Set output amount if (txNew.vout.size() == 3) { txNew.vout[1].nValue = (nCredit / 2 / CENT) * CENT; txNew.vout[2].nValue = nCredit - txNew.vout[1].nValue; } else txNew.vout[1].nValue = nCredit;
// Sign int nIn = 0; BOOST_FOREACH(const CWalletTx* pcoin, vwtxPrev) { if (!SignSignature(*this, *pcoin, txNew, nIn++)) return error("CreateCoinStake : failed to sign coinstake"); }
// Limit size unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION); if (nBytes >= MAX_BLOCK_SIZE_GEN/5) return error("CreateCoinStake : exceeded coinstake size limit");
// Successfully generated coinstake return true; }
Но она не проходит проверку if (nCredit == 0 || nCredit > nBalance - nReserveBalance). А именно потому, что nCredit равен нулю. Что это вообще за переменная? За что она отвечает? Она должна суммировать какие-то значения здесь nCredit += pcoin.first->vout[pcoin.second].nValue;Но этого не просходит.
|
|
|
|
gorus5 (OP)
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 03, 2018, 09:43:18 AM |
|
Пошел дальше по стеку вызовов, обнаружил где лежит корень проблемы. А проблема в методе GetStakeModifierSelectionInterval. Вернее в том, что новое генерируемое значение nStakeModifierTime не попадает в промежуток возвращенный этим методом. Там условие while (nStakeModifierTime < pindexFrom->GetBlockTime() + nStakeModifierSelectionInterval) Соотвестенно чтобы цикл закончился надо чтобы значение nStakeModifierTime стало больше чем pindexFrom->GetBlockTime() плюс этот интервал. А метод генерирует значение довольно больше, 21135. Поставил вручнуе значение 100 - сразу заработало, блок сгенерировался и принялся. От чего зависит значение этого метода? Как сделать чтобы он возвращал правильное значение?
|
|
|
|
Coin-1
Legendary
Offline
Activity: 2632
Merit: 2304
|
|
April 10, 2018, 04:01:41 AM |
|
Пошел дальше по стеку вызовов, обнаружил где лежит корень проблемы. А проблема в методе GetStakeModifierSelectionInterval. Вернее в том, что новое генерируемое значение nStakeModifierTime не попадает в промежуток возвращенный этим методом. Там условие while (nStakeModifierTime < pindexFrom->GetBlockTime() + nStakeModifierSelectionInterval) Соотвестенно чтобы цикл закончился надо чтобы значение nStakeModifierTime стало больше чем pindexFrom->GetBlockTime() плюс этот интервал. А метод генерирует значение довольно больше, 21135. Поставил вручнуе значение 100 - сразу заработало, блок сгенерировался и принялся. От чего зависит значение этого метода? Как сделать чтобы он возвращал правильное значение? Ага, вот что за монета с PoW и PoS. nStakeModifierSelectionInterval равен 21135, или (pindexFrom->GetBlockTime() + nStakeModifierSelectionInterval) равно 21135?
|
|
|
|
|