Author

Topic: Некорректно генерируются PoS блоки. В чем при (Read 214 times)

legendary
Activity: 2618
Merit: 2304
Пошел дальше по стеку вызовов, обнаружил где лежит корень проблемы.
А проблема в методе GetStakeModifierSelectionInterval.
Вернее в том, что новое генерируемое значение nStakeModifierTime не попадает в промежуток возвращенный этим методом.
Там условие
Code:
while (nStakeModifierTime < pindexFrom->GetBlockTime() + nStakeModifierSelectionInterval)
Соотвестенно чтобы цикл закончился надо чтобы значение nStakeModifierTime стало больше чем pindexFrom->GetBlockTime() плюс этот интервал. А метод генерирует значение довольно больше, 21135. Поставил вручнуе значение 100 - сразу заработало, блок сгенерировался и принялся.
От чего зависит значение этого метода? Как сделать чтобы он возвращал правильное значение?
Ага, вот что за монета с PoW и PoS.

nStakeModifierSelectionInterval равен 21135, или
(pindexFrom->GetBlockTime() + nStakeModifierSelectionInterval) равно 21135?
newbie
Activity: 24
Merit: 0
Пошел дальше по стеку вызовов, обнаружил где лежит корень проблемы.
А проблема в методе GetStakeModifierSelectionInterval.
Вернее в том, что новое генерируемое значение nStakeModifierTime не попадает в промежуток возвращенный этим методом.
Там условие
Code:
while (nStakeModifierTime < pindexFrom->GetBlockTime() + nStakeModifierSelectionInterval)
Соотвестенно чтобы цикл закончился надо чтобы значение nStakeModifierTime стало больше чем pindexFrom->GetBlockTime() плюс этот интервал. А метод генерирует значение довольно больше, 21135. Поставил вручнуе значение 100 - сразу заработало, блок сгенерировался и принялся.
От чего зависит значение этого метода? Как сделать чтобы он возвращал правильное значение?
newbie
Activity: 24
Merit: 0
Выяснил следующее - CoinStake транзация пытается сгенерироваться в методе wallet.cpp/CreateCoinStake как и положено.
Code:
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 vwtxPrev;

    set > 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        {
            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 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;
Но этого не просходит.
newbie
Activity: 24
Merit: 0
Я знаю что не будет работать. Но монеты есть, и staking горит.
Ок, спасибо за помощь)

Кстати, с какого возраста монеты начинают майнить? Вы этот вопрос изучили?
В оригинальном коде стоит 8 часов минимум, но я ставил меньше для теста.
newbie
Activity: 10
Merit: 0
Я знаю что не будет работать. Но монеты есть, и staking горит.
Ок, спасибо за помощь)

Кстати, с какого возраста монеты начинают майнить? Вы этот вопрос изучили?
newbie
Activity: 24
Merit: 0
Если высота блоков не достигла значения nLastPOWBlock, это ведь не значит что PoS не может работать?

PoS не будет работать если нет созревших монет.
Буду копать инфу по данной ошибке, по итогам отпишусь.
Может кто-то из форумчан встречался с этой проблемой и ответит Вам. Удачи!
Я знаю что не будет работать. Но монеты есть, и staking горит.
Ок, спасибо за помощь)
newbie
Activity: 10
Merit: 0
Если высота блоков не достигла значения nLastPOWBlock, это ведь не значит что PoS не может работать?

PoS не будет работать если нет созревших монет.
Буду копать инфу по данной ошибке, по итогам отпишусь.
Может кто-то из форумчан встречался с этой проблемой и ответит Вам. Удачи!
newbie
Activity: 24
Merit: 0
Уточните еще один момент. С какой высоты начинаются PoS блоки?
Я пробовал и ставить маленькое (100) и оставлять как есть - результат тот же.
Если высота блоков не достигла значения nLastPOWBlock, это ведь не значит что PoS не может работать?
Просто до того времени может быть как PoW так и PoS, а когда высота станет больше, будут приниматься только PoS.

Интересно  Smiley
Сколько блоков для подтверждения... ?
Поставил nCoinbaseMaturity = nStakeMinConfirmations = 10.
newbie
Activity: 10
Merit: 0
Уточните еще один момент. С какой высоты начинаются PoS блоки?
Я пробовал и ставить маленькое (100) и оставлять как есть - результат тот же.
Если высота блоков не достигла значения nLastPOWBlock, это ведь не значит что PoS не может работать?
Просто до того времени может быть как PoW так и PoS, а когда высота станет больше, будут приниматься только PoS.

Интересно  Smiley
Сколько блоков для подтверждения... ?
newbie
Activity: 24
Merit: 0
Уточните еще один момент. С какой высоты начинаются PoS блоки?
В блэккойне стоит значение 10000.
Я пробовал и ставить маленькое (100) и оставлять как есть - результат тот же.
Если высота блоков не достигла значения nLastPOWBlock, это ведь не значит что PoS не может работать?
Просто до того времени может быть как PoW так и PoS, а когда высота станет больше, будут приниматься только PoS.
newbie
Activity: 10
Merit: 0
Уточните еще один момент. С какой высоты начинаются PoS блоки?
newbie
Activity: 24
Merit: 0
Я клонирую альткойн. Все работает отлично. За исключеним самого главного - не генерируются PoS блоки.

Можно узнать какой альткоин Вы клонируете?

Советую посмотреть начались ли PoS блоки в том альткоине, который Вы клонируете.
Если это баг не Ваш, то скорее всего его решит команда, чей код Вы берете за исходный.

BlackCoin. Да, там есть PoS, он уже давно только на нем и работает.
newbie
Activity: 10
Merit: 0
Я клонирую альткойн. Все работает отлично. За исключеним самого главного - не генерируются PoS блоки.

Можно узнать какой альткоин Вы клонируете?

Советую посмотреть начались ли PoS блоки в том альткоине, который Вы клонируете.
Если это баг не Ваш, то скорее всего его решит команда, чей код Вы берете за исходный.
newbie
Activity: 24
Merit: 0
Я клонирую альткойн. Все работает отлично. За исключеним самого главного - не генерируются PoS блоки.
Есть несколько клиентов, они соеденены, значок Staking светится (хотя всегда пишет network weight - 0).
На обычном PoW майнинге все работает как надо, но моя цель в конечном итоге перевести валюту только на PoS, а он не работает.
Когда майнинг выключен, новые блоки не генерируются и соответсвенно транзации не проходят.

Пошарив код и дебаг логи, обнаружил что блоки генерируются. НО не принимаются, т.к. они имеют некорректную структуру.
А именно не проходит последнее условие в проверке isCoinStake
Code:
    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)
Code:
{
   "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 в первой транзации (именно в первой, т.е. по порядку - второй).
Никак не могу понять в чем причина. Я в коде ничего не менял что имело бы отношение к этому.
Jump to: