diff --git a/README.md b/README.md index f09ae2a1b2c62..3054edb17b7d7 100644 --- a/README.md +++ b/README.md @@ -50,10 +50,10 @@ More information at [ionomy.com](https://www.ionomy.com) Visit our ANN thread at Coin specifications || :------------ | :---: -Algorithm | Quark | +Algorithm | hybrid: X11 (PoW) / SHA-256 (PoS) | Retargeting Algorithm | DGW | Difficulty Retargeting | Every Block -Max Coin Supply | 48,035,935.4 ION +Max Coin Supply | Unlimited Premine | 16,400,000 ION* _*16,629,951 Ion Premine was burned in block [1](https://chainz.cryptoid.info/ion/block.dws?000000ed2f68cd6c7935831cc1d473da7c6decdb87e8b5dba0afff0b00002690.htm)_ @@ -68,28 +68,32 @@ _*16,629,951 Ion Premine was burned in block [1](https://chainz.cryptoid.info/io ### PoW Rewards Breakdown -Block Height | Masternodes | Miner | Total | - ----------: | ----------: | ----: | ----: | -2-454 | 50% (11.5 ION) | 50% (11.5 ION) | 10,419 ION | +Block Height | Masternodes | Miner | Total | Max coin supply | + ----------: | ----------: | ----: | ----: | ----: | +2-454 | 50% (11.5 ION) | 50% (11.5 ION) | 10,419 ION | 16,410,419 ION | ### PoS/PoW Rewards Breakdown -Block Height | Masternodes | Miner | Budget | - ----------: | ----------: | ----: | -----: | -455-1000 | 50% (11.5 ION) | 50% (11.5 ION)| 12,558 ION | +Block Height | Masternodes | Miner/Minter | Budget | Max coin supply | + ----------: | ----------: | ----: | -----: | ----: | +455-1000 | 50% (11.5 ION) | 50% (11.5 ION)| 12,558 ION | 16,422,977 ION | ### PoS Rewards Breakdown -Block Height | Masternodes | Miner | Budget | - ----------: | ----------: | ----: | -----: | -1001-125147 | 50% (11.5 ION) | 50% (11.5 ION) | 2,855,381 ION | -125148-550001 | 50% (8.5 ION) | 50% (8.5 ION) | 7,222,518 ION | -550002-551441 | 50% (0.01 ION) | 50% (0.01 ION) | 28.8 ION | -551442-570063 | 50% (8.5 ION) | 50% (8.5 ION) | 316,574 ION | -570064-1013539 | 50% (5.75 ION) | 50% (5.75 ION) | 5,099,974 ION | -1013540-1457015 | 50% (2.875 ION) | 50% (2.875 ION) | 2,549,987 ION | -1457016-3677391 | 50% (0.925 ION) | 50% (0.925 ION) | 4,107,695.6 ION | -3677392-50981391 | 50% (0.1 ION) | 50% (0.1 ION) | 9,460,800 ION | +Block Height | Masternodes | Minter | Budget | Max coin supply | + ----------: | ----------: | ----: | -----: | ----: | +1001-125146 | 50% (11.5 ION) | 50% (11.5 ION) | 2,855,358 ION | 19,278,335 ION | +125147-550001 | 50% (8.5 ION) | 50% (8.5 ION) | 7,222,535 ION | 26,500,870 ION | +550002-551441 | 50% (0.01 ION) | 50% (0.01 ION) | 28.8 ION | 26,500,898.8 ION | +551442-570063 | 50% (8.5 ION) | 50% (8.5 ION) | 316,574 ION | 26,817,472.8 ION | +570064-1013539 | 50% (5.75 ION) | 50% (5.75 ION) | 5,099,974 ION | 31,917,446.8 ION | +1013540-1600000 | 50% (2.875 ION) | 50% (2.875 ION) | 3,372,150.75 ION | 35,289,597.55 ION | + +### Hybrid PoS/PoW Rewards Breakdown + +Block Height | Masternodes | Miner | Minter | Annual (ION) | Annual (ELEC) | + ----------: | ----------: | ----: | -----: | ----: | ----: | +1600000 - | 70% ION (0.35 ION) | 100% ELEC (0.5 ELEC)| 30% ION (0.15 ION)| 262,800 ION | 262,800 ELEC | ## Ion Core FAQ/Help _get support/chat with us or send your request per [Email](mail:support@ionomy.com). You can also join our discord or encrypted chat on matrix._ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 3c5e4b42c3467..bfadff1bb7462 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -896,7 +896,7 @@ class CRegTestParams : public CChainParams { nPoolMinParticipants = 3; nPoolMaxParticipants = 5; - // privKey: cP4EKFyJsHT39LDqgdcB43Y3YXjNyjb5Fuas1GQSeAtjnZWmZEQK + // privKey: 93QPD8M8SrVb4yL3E679sCGztzy1NRWYH3fs2wJQr2LMKnppFCJ vSporkAddresses = {"gRgAY9dX7kN3tLNeVPQ8YoVGJdeNiE2Ubr"}; nMinSporkKeys = 1; // regtest usually has no masternodes in most tests, so don't check for upgraged MNs diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index 737ad568713ed..904ca94b3e6db 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -4,6 +4,7 @@ #include "tx_verify.h" +#include "chainparams.h" #include "consensus.h" #include "primitives/transaction.h" #include "script/interpreter.h" @@ -215,7 +216,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, const boo return true; } -bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee) +bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee, const Consensus::Params& params) { // are the actual inputs available? if (!inputs.HaveInputs(tx)) { @@ -230,22 +231,22 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c assert(!coin.IsSpent()); // If prev is coinbase, coinstake or group authority confirguration, check that it's matured - if (coin.IsCoinStake() && nSpendHeight - coin.nHeight < (nSpendHeight <= 100 ? (int)10 : Params().nCoinbaseMaturity)) { + if (coin.IsCoinStake() && nSpendHeight - coin.nHeight < (nSpendHeight <= 100 ? (int)10 : params.nCoinbaseMaturity)) { return state.Invalid(false, REJECT_INVALID, "bad-txns-premature-spend-of-coinstake", strprintf("tried to spend coinstake at depth %d", nSpendHeight - coin.nHeight)); } - if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < (nSpendHeight <= 100 ? (int)10 : Params().nCoinbaseMaturity)) { + if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < (nSpendHeight <= 100 ? (int)10 : params.nCoinbaseMaturity)) { return state.Invalid(false, REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight)); } if (IsOutputGroupedAuthority(coin.out)) { - if (nSpendHeight - coin.nHeight < Params().nOpGroupNewRequiredConfirmations) { + if (nSpendHeight - coin.nHeight < params.nOpGroupNewRequiredConfirmations) { return state.Invalid( - error("CheckInputs() : tried to use a token authority before it reached maturity (%d confirmations)", Params().nOpGroupNewRequiredConfirmations), + error("CheckInputs() : tried to use a token authority before it reached maturity (%d confirmations)", params.nOpGroupNewRequiredConfirmations), REJECT_INVALID, "bad-txns-premature-use-of-token-authority"); } } diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h index 2f98a23e107a3..250d90fd2e535 100644 --- a/src/consensus/tx_verify.h +++ b/src/consensus/tx_verify.h @@ -6,6 +6,7 @@ #define BITCOIN_CONSENSUS_TX_VERIFY_H #include "amount.h" +#include "consensus/params.h" #include #include @@ -27,7 +28,7 @@ namespace Consensus { * @param[out] txfee Set to the transaction fee if successful. * Preconditions: tx.IsCoinBase() is false. */ -bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee); +bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee, const Consensus::Params& params); } // namespace Consensus /** Auxiliary functions for transaction validation (ideally should not be exposed) */ diff --git a/src/net.cpp b/src/net.cpp index d811ca3baa95e..8895ee6e223d1 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -21,6 +21,7 @@ #include "primitives/transaction.h" #include "netbase.h" #include "scheduler.h" +#include "spork.h" #include "ui_interface.h" #include "utilstrencodings.h" #include "validation.h" @@ -2967,6 +2968,10 @@ void CConnman::RelayTransaction(const CTransaction& tx) } } +void CConnman::RelayInv(CInv &inv) { + RelayInv(inv, GetMinPeerVersion()); +} + void CConnman::RelayInv(CInv &inv, const int minProtoVersion) { LOCK(cs_vNodes); for (const auto& pnode : vNodes) @@ -2974,6 +2979,11 @@ void CConnman::RelayInv(CInv &inv, const int minProtoVersion) { pnode->PushInventory(inv); } +void CConnman::RelayInvFiltered(CInv &inv, const CTransaction& relatedTx) +{ + RelayInvFiltered(inv, relatedTx, GetMinPeerVersion()); +} + void CConnman::RelayInvFiltered(CInv &inv, const CTransaction& relatedTx, const int minProtoVersion) { LOCK(cs_vNodes); @@ -2989,6 +2999,11 @@ void CConnman::RelayInvFiltered(CInv &inv, const CTransaction& relatedTx, const } } +void CConnman::RelayInvFiltered(CInv &inv, const uint256& relatedTxHash) +{ + RelayInvFiltered(inv, relatedTxHash, GetMinPeerVersion()); +} + void CConnman::RelayInvFiltered(CInv &inv, const uint256& relatedTxHash, const int minProtoVersion) { LOCK(cs_vNodes); @@ -3396,3 +3411,11 @@ uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup.data(), vchNetGroup.size()).Finalize(); } + +int CConnman::GetMinPeerVersion() { + // SPORK_11 is used for 95705 (v3.3+) + if (sporkManager.IsSporkActive(SPORK_8_NEW_PROTOCOL_ENFORCEMENT)) + return MIN_PEER_PROTO_VERSION_AFTER_ENFORCEMENT; + + return MIN_PEER_PROTO_VERSION_BEFORE_ENFORCEMENT; +} diff --git a/src/net.h b/src/net.h index e6d1d9a9b2e7d..2cf99bd320cbc 100644 --- a/src/net.h +++ b/src/net.h @@ -343,10 +343,13 @@ class CConnman void ReleaseNodeVector(const std::vector& vecNodes); void RelayTransaction(const CTransaction& tx); - void RelayInv(CInv &inv, const int minProtoVersion = MIN_PEER_PROTO_VERSION); - void RelayInvFiltered(CInv &inv, const CTransaction &relatedTx, const int minProtoVersion = MIN_PEER_PROTO_VERSION); + void RelayInv(CInv &inv, const int minProtoVersion); + void RelayInv(CInv &inv); + void RelayInvFiltered(CInv &inv, const CTransaction &relatedTx, const int minProtoVersion); + void RelayInvFiltered(CInv &inv, const CTransaction &relatedTx); // This overload will not update node filters, so use it only for the cases when other messages will update related transaction data in filters - void RelayInvFiltered(CInv &inv, const uint256 &relatedTxHash, const int minProtoVersion = MIN_PEER_PROTO_VERSION); + void RelayInvFiltered(CInv &inv, const uint256 &relatedTxHash, const int minProtoVersion); + void RelayInvFiltered(CInv &inv, const uint256 &relatedTxHash); void RemoveAskFor(const uint256& hash); // Addrman functions @@ -448,6 +451,8 @@ class CConnman void WakeMessageHandler(); void WakeSelect(); + int GetMinPeerVersion(); + private: struct ListenSocket { SOCKET socket; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 13b3dd2215111..fb18d23ad967b 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1820,12 +1820,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return false; } - if (nVersion < MIN_PEER_PROTO_VERSION) + if (nVersion < connman->GetMinPeerVersion()) { // disconnect from peers older than this proto version LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion); connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, - strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION))); + strprintf("Version must be %d or greater", connman->GetMinPeerVersion()))); pfrom->fDisconnect = true; return false; } diff --git a/src/pos/kernel.cpp b/src/pos/kernel.cpp index 4ab9e27a09687..e3df03f73b473 100644 --- a/src/pos/kernel.cpp +++ b/src/pos/kernel.cpp @@ -11,6 +11,7 @@ #include "wallet/db.h" #include "kernel.h" #include "policy/policy.h" +#include "pow.h" #include "script/interpreter.h" #include "timedata.h" #include "util.h" @@ -91,7 +92,7 @@ static bool SelectBlockFromCandidates( // the selection hash is divided by 2**32 so that proof-of-stake block // is always favored over proof-of-work block. this is to preserve // the energy efficiency property - if (pindex->IsProofOfStake()) + if (IsProofOfStakeHeight(pindex->nHeight, Params().GetConsensus())) hashSelection = ArithToUint256(UintToArith256(hashSelection) >> 32); if (fSelected && UintToArith256(hashSelection) < UintToArith256(hashBest)) { diff --git a/src/pow.cpp b/src/pow.cpp index 9822f2b782ae2..8a857a4b9024a 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -417,12 +417,12 @@ unsigned int static GetNextWorkRequiredOrig(const CBlockIndex* pindexLast, const if (pindexLast == NULL) return UintToArith256(bnTargetLimit).GetCompact(); // genesis block const CBlockIndex* pindexPrev = pindexLast; - while (pindexPrev && pindexPrev->pprev && (pindexPrev->IsProofOfStake() != fProofOfStake)) + while (pindexPrev && pindexPrev->pprev && (IsProofOfStakeHeight(pindexPrev->nHeight, params) != fProofOfStake)) pindexPrev = pindexPrev->pprev; if (pindexPrev == NULL) return UintToArith256(bnTargetLimit).GetCompact(); // first block const CBlockIndex* pindexPrevPrev = pindexPrev->pprev; - while (pindexPrevPrev && pindexPrevPrev->pprev && (pindexPrevPrev->IsProofOfStake() != fProofOfStake)) + while (pindexPrevPrev && pindexPrevPrev->pprev && (IsProofOfStakeHeight(pindexPrevPrev->nHeight, params) != fProofOfStake)) pindexPrevPrev = pindexPrevPrev->pprev; if (pindexPrevPrev == NULL) return UintToArith256(bnTargetLimit).GetCompact(); // second block @@ -452,10 +452,8 @@ unsigned int static GetNextWorkRequiredOrig(const CBlockIndex* pindexLast, const return bnNew.GetCompact(); } -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params, const bool fHybridPow) -{ +bool IsProofOfStakeHeight(const int nHeight, const Consensus::Params& params) { bool fProofOfStake; - const int nHeight = pindexLast->nHeight + 1; if (nHeight >= params.POSStartHeight){ fProofOfStake = true; } else if (Params().NetworkIDString() == CBaseChainParams::MAIN) { @@ -505,6 +503,13 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const Consensus: } else { fProofOfStake = false; } + return fProofOfStake; +} + +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params, const bool fHybridPow) +{ + const int nHeight = pindexLast->nHeight + 1; + bool fProofOfStake = IsProofOfStakeHeight(nHeight, params); // this is only active on devnets if (pindexLast->nHeight < params.nMinimumDifficultyBlocks) { diff --git a/src/pow.h b/src/pow.h index 313fb73ac86f5..c491bcde3594c 100644 --- a/src/pow.h +++ b/src/pow.h @@ -19,4 +19,6 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const Consensus: /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); +bool IsProofOfStakeHeight(const int nHeight, const Consensus::Params& params); + #endif // BITCOIN_POW_H diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 610af07e4533e..ad87a50548ff6 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -282,7 +282,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco if (wtx.IsCoinBase() || wtx.IsCoinStake()) { - int numBlocksToMaturity = Consensus::Params().nCoinbaseMaturity; + int numBlocksToMaturity = Params().GetConsensus().nCoinbaseMaturity; strHTML += "
" + tr("Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.").arg(QString::number(numBlocksToMaturity)) + "
"; } diff --git a/src/script/standard.h b/src/script/standard.h index 0b2d432a144d6..daf3dfd99f337 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -27,7 +27,7 @@ class CScriptID : public uint160 CScriptID(const uint160& in) : uint160(in) {} }; -static const unsigned int MAX_OP_RETURN_RELAY = 83; //!< bytes (+1 for OP_RETURN, +2 for the pushdata opcodes) +static const unsigned int MAX_OP_RETURN_RELAY = 184; //!< bytes (+1 for OP_RETURN, +5 for the OpRetGroupId, +178 for GroupDescData) extern bool fAcceptDatacarrier; extern unsigned nMaxDatacarrierBytes; diff --git a/src/spork.cpp b/src/spork.cpp index 35d3c6f3bcebc..eb05ce4044e7d 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -24,7 +24,7 @@ std::vector sporkDefs = { MAKE_SPORK_DEF(SPORK_5_MASTERNODE_BUDGET_ENFORCEMENT, 4070908800), // OFF MAKE_SPORK_DEF(SPORK_6_MASTERNODE_ENABLE_SUPERBLOCKS, 4070908800), // OFF MAKE_SPORK_DEF(SPORK_7_MASTERNODE_PAY_UPDATED_NODES, 1521851265), // GMT: Saturday, March 24, 2018 12:27:45 AM (OFF 4070908800) - MAKE_SPORK_DEF(SPORK_8_NEW_PROTOCOL_ENFORCEMENT, 1556668800), // GMT: Wednesday, May 1, 2019 12:00:00 AM (OFF 4070908800) + MAKE_SPORK_DEF(SPORK_8_NEW_PROTOCOL_ENFORCEMENT, 4070908800), // OFF MAKE_SPORK_DEF(SPORK_9_ZEROCOIN_MAINTENANCE_MODE, 4070908800), // OFF MAKE_SPORK_DEF(SPORK_10_TOKENGROUP_MAINTENANCE_MODE, 4070908800), // OFF MAKE_SPORK_DEF(SPORK_11_NEW_PROTOCOL_ENFORCEMENT_2, 4070908800), // OFF diff --git a/src/tokens/rpctokenwallet.cpp b/src/tokens/rpctokenwallet.cpp index ae3b030372a30..f4882c4d39147 100644 --- a/src/tokens/rpctokenwallet.cpp +++ b/src/tokens/rpctokenwallet.cpp @@ -336,11 +336,12 @@ extern UniValue gettokenbalance(const JSONRPCRequest& request) if (request.fHelp) throw std::runtime_error( - "gettokenbalance ( \"groupid\" )\n" + "gettokenbalance ( \"groupid\" ) ( \"address\" )\n" "\nIf groupID is not specified, returns all tokens with a balance (including token authorities).\n" "If a groupID is specified, returns the balance of the specified token group.\n" "\nArguments:\n" - "1. \"groupid\" (string, optional) the token group identifier\n" + "1. \"groupid\" (string, optional) the token group identifier to filter\n" + "2. \"address\" (string, optional) the ION address to filter\n" "\n" "\nExamples:\n" + HelpExampleCli("gettokenbalance", "groupid ionrt1zwm0kzlyptdmwy3849fd6z5epesnjkruqlwlv02u7y6ymf75nk4qs6u85re") + @@ -712,8 +713,8 @@ extern UniValue sendtoken(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1) throw std::runtime_error( - "sendtoken \"groupid\" \"address\" amount \n" - "\nSends token to a given address.\n" + "sendtoken \"groupid\" \"address\" amount ( \"address\" amount ) ( .. ) \n" + "\nSends token to a given address. Specify multiple addresses and amounts for multiple recipients.\n" "\n" "1. \"groupid\" (string, required) the group identifier\n" "2. \"address\" (string, required) the destination address\n" diff --git a/src/transactionrecord.cpp b/src/transactionrecord.cpp index 5ad4ed91c89a9..926843a21a0d7 100644 --- a/src/transactionrecord.cpp +++ b/src/transactionrecord.cpp @@ -8,6 +8,7 @@ #include "base58.h" #include "consensus/consensus.h" #include "validation.h" +#include "pos/rewards.h" #include "timedata.h" #include "wallet/wallet.h" @@ -25,6 +26,140 @@ bool TransactionRecord::showTransaction(const CWalletTx &wtx) return true; } +bool DecomposeReward(const CWallet* wallet, const CWalletTx& wtx, const CTxDestination address, const bool fPos, std::vector &records) { + std::map coinstakeRewards; + std::map coinbaseRewards; + std::map MNRewards; + + // Only a stake reward, so the default decompose function suffices + if (wtx.tx->vout.size() < (fPos ? 3 : 2)) return false; + + const Consensus::Params& consensusParams = Params().GetConsensus(); + + // When the block has not confirmed - or when not yet in hybrid mode, the default decompose function suffices + const CBlockIndex* pindexWtx; + const int nBlockDepth = wtx.GetDepthInMainChain(pindexWtx); + if (nBlockDepth <= 0 || !pindexWtx) return false; + const int nBlockHeight = pindexWtx->nHeight; + if (nBlockHeight < consensusParams.POSPOWStartHeight) return false; + + CBlockReward blockReward(nBlockHeight, 0, fPos, consensusParams); + + if (fPos) { + // When no coinstake value can be determined, the default decompose function suffices + COutPoint prevout = wtx.tx->vin[0].prevout; + uint256 hashBlock; + CTransactionRef txIn; + if (!GetTransaction(prevout.hash, txIn, consensusParams, hashBlock, true)) return false; + if (txIn->vout.size() < prevout.n + 1) return false; + + CAmount nStakeInValue = txIn->vout[prevout.n].nValue; + + CAmount wtxOutValue = 0; + for (auto txOut : wtx.tx->vout) { + wtxOutValue += txOut.nValue; + } + CAmount nFees = (wtxOutValue - nStakeInValue) - blockReward.GetTotalRewards().IONAmount; + blockReward.AddHybridFees(nFees / 0.8 + 1); // 20% of the fees were burned. Add 1 for slack, to avoid fetching the full block. + + CAmount nStakeValue = blockReward.GetCoinstakeReward().IONAmount; + + bool fAllCoinstakesFound = false; + CAmount nStakeValueFound = 0; + for (int i = 1; i < (int)wtx.tx->vout.size(); i++) { + + CTxOut curOut = wtx.tx->vout[i]; + if (!fAllCoinstakesFound) { + if (nStakeValueFound + curOut.nValue <= nStakeInValue + nStakeValue) { + nStakeValueFound += curOut.nValue; + coinstakeRewards.insert(std::make_pair(i, curOut)); + } else { + MNRewards.insert(std::make_pair(i, curOut)); + fAllCoinstakesFound = true; + } + } else { + MNRewards.insert(std::make_pair(i, curOut)); + } + } + } else { + CAmount nCoinbaseValue = blockReward.GetCoinbaseReward().IONAmount; + + bool fAllCoinbasesFound = false; + CAmount nCoinbaseValueFound = 0; + for (int i = 0; i < (int)wtx.tx->vout.size(); i++) { + + CTxOut curOut = wtx.tx->vout[i]; + if (!fAllCoinbasesFound) { + if (nCoinbaseValueFound + curOut.nValue <= nCoinbaseValue) { + nCoinbaseValueFound += curOut.nValue; + coinbaseRewards.insert(std::make_pair(i, curOut)); + } else { + MNRewards.insert(std::make_pair(i, curOut)); + fAllCoinbasesFound = true; + } + } else { + MNRewards.insert(std::make_pair(i, curOut)); + } + } + } + + int64_t nTime = wtx.GetTxTime(); + const uint256 hash = wtx.GetHash(); + std::map mapValue = wtx.mapValue; + + TransactionRecord stakeRecord(hash, nTime); + if (coinstakeRewards.size() > 0) { + if (isminetype mine = wallet->IsMine(wtx.tx->vout[1])){ + // Stake reward + stakeRecord.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; + stakeRecord.type = TransactionRecord::StakeMint; + stakeRecord.strAddress = CBitcoinAddress(address).ToString(); + stakeRecord.address.SetString(stakeRecord.strAddress); + stakeRecord.txDest = stakeRecord.address.Get(); + for (auto stakeReward : coinstakeRewards) { + stakeRecord.credit += wallet->GetCredit(stakeReward.second, ISMINE_ALL); + } + stakeRecord.credit -= wtx.GetDebit(ISMINE_ALL); + records.push_back(stakeRecord); + } + } + + TransactionRecord coinbaseRecord(hash, nTime); + if (coinbaseRewards.size() > 0) { + if (isminetype mine = wallet->IsMine(wtx.tx->vout[0])){ + // Stake reward + coinbaseRecord.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; + coinbaseRecord.type = TransactionRecord::Generated; + coinbaseRecord.strAddress = CBitcoinAddress(address).ToString(); + coinbaseRecord.address.SetString(coinbaseRecord.strAddress); + coinbaseRecord.txDest = coinbaseRecord.address.Get(); + for (auto coinbaseReward : coinbaseRewards) { + coinbaseRecord.credit += wallet->GetCredit(coinbaseReward.second, ISMINE_ALL); + } + records.push_back(coinbaseRecord); + } + } + + TransactionRecord MNRecord(hash, nTime); + if (MNRewards.size() > 0) { + auto MNReward = MNRewards.begin(); + // Masternode reward + if (isminetype mine = wallet->IsMine(MNReward->second)) { + CTxDestination destMN; + ExtractDestination(MNReward->second.scriptPubKey, destMN); + MNRecord.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; + MNRecord.type = TransactionRecord::MNReward; + MNRecord.strAddress = CBitcoinAddress(destMN).ToString(); + MNRecord.address.SetString(MNRecord.strAddress); + MNRecord.txDest = MNRecord.address.Get(); + MNRecord.credit = MNReward->second.nValue; + records.push_back(MNRecord); + } + } + + return true; +} + /* * Decompose CWallet transaction to model transaction records. */ @@ -44,6 +179,10 @@ std::vector TransactionRecord::decomposeTransaction(const CWa if (!ExtractDestination(wtx.tx->vout[1].scriptPubKey, address)) return parts; + if (DecomposeReward(wallet, wtx, address, true, parts)) { + return parts; + } + if (isminetype mine = wallet->IsMine(wtx.tx->vout[1])) { // ION stake reward sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; @@ -68,6 +207,13 @@ std::vector TransactionRecord::decomposeTransaction(const CWa parts.push_back(sub); } else if (nNet > 0 || wtx.IsCoinBase()) { + if (wtx.tx->IsCoinBase()) { + TransactionRecord sub(hash, nTime); + CTxDestination address; + if (ExtractDestination(wtx.tx->vout[0].scriptPubKey, address) && DecomposeReward(wallet, wtx, address, false, parts)) { + return parts; + } + } // // Credit // diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 1c3c79a493fa2..cd97931e2e213 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -779,7 +779,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem continue; const Coin &coin = pcoins->AccessCoin(txin.prevout); if (nCheckFrequency != 0) assert(!coin.IsSpent()); - if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < Consensus::Params().nCoinbaseMaturity)) { + if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < Params().GetConsensus().nCoinbaseMaturity)) { txToRemove.insert(it); break; } @@ -1010,7 +1010,7 @@ static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& m { CValidationState state; CAmount txfee = 0; - bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, txfee); + bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, txfee, Params().GetConsensus()); assert(fCheckResult); UpdateCoins(tx, mempoolDuplicate, 1000000); } diff --git a/src/validation.cpp b/src/validation.cpp index ca64bc791c3f8..1d4d9655a74a6 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -696,7 +696,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool } // end LOCK(pool.cs) CAmount nFees = 0; - if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), nFees)) { + if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), nFees, chainparams.GetConsensus())) { return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state)); } @@ -2111,7 +2111,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd } else if (!tx->IsCoinBase()) { CAmount txfee = 0; - if (!Consensus::CheckTxInputs(*tx, state, view, pindex->nHeight, txfee)) { + if (!Consensus::CheckTxInputs(*tx, state, view, pindex->nHeight, txfee, Params().GetConsensus())) { return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx->GetHash().ToString(), FormatStateMessage(state)); } nFees += txfee; diff --git a/src/version.h b/src/version.h index 464c73aa13caa..f0868cb011796 100644 --- a/src/version.h +++ b/src/version.h @@ -20,7 +20,8 @@ static const int INIT_PROTO_VERSION = 901; static const int GETHEADERS_VERSION = 96000; //! disconnect from peers older than this proto version -static const int MIN_PEER_PROTO_VERSION = 95705; +static const int MIN_PEER_PROTO_VERSION_BEFORE_ENFORCEMENT = 95705; +static const int MIN_PEER_PROTO_VERSION_AFTER_ENFORCEMENT = 96000; //! nTime field added to CAddress, starting with this version; //! if possible, avoid requesting addresses nodes older than this diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 7f225dedaa2ca..f579da157e257 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -9,6 +9,7 @@ #include "base58.h" #include "checkpoints.h" #include "chain.h" +#include "chainparams.h" #include "wallet/coincontrol.h" #include "consensus/consensus.h" #include "consensus/validation.h" @@ -6074,8 +6075,8 @@ int CMerkleTx::GetBlocksToMaturity() const int depth = GetDepthInMainChain(); int minBlocksToMaturity = 0; if (IsAnyOutputGroupedAuthority((CTransaction(*this)))) - minBlocksToMaturity = std::max(0, (Consensus::Params().nOpGroupNewRequiredConfirmations + 1) - depth); - return std::max(minBlocksToMaturity, (Consensus::Params().nCoinbaseMaturity + 1) - depth); + minBlocksToMaturity = std::max(0, (Params().GetConsensus().nOpGroupNewRequiredConfirmations + 1) - depth); + return std::max(minBlocksToMaturity, (Params().GetConsensus().nCoinbaseMaturity + 1) - depth); } diff --git a/test/functional/dip3-deterministicmns.py b/test/functional/dip3-deterministicmns.py index c565dfc4d6248..305ea476597ee 100755 --- a/test/functional/dip3-deterministicmns.py +++ b/test/functional/dip3-deterministicmns.py @@ -23,7 +23,7 @@ def set_test_params(self): self.setup_clean_chain = True self.extra_args = ["-budgetparams=10:10:10"] - self.extra_args += ["-sporkkey=cP4EKFyJsHT39LDqgdcB43Y3YXjNyjb5Fuas1GQSeAtjnZWmZEQK"] + self.extra_args += ["-sporkkey=93QPD8M8SrVb4yL3E679sCGztzy1NRWYH3fs2wJQr2LMKnppFCJ"] self.extra_args += ["-dip3params=135:150"] diff --git a/test/functional/sporks.py b/test/functional/sporks.py index 9b88c26843d4d..a7dfce3d6a866 100755 --- a/test/functional/sporks.py +++ b/test/functional/sporks.py @@ -14,7 +14,7 @@ class SporkTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 3 self.setup_clean_chain = True - self.extra_args = [["-sporkkey=cP4EKFyJsHT39LDqgdcB43Y3YXjNyjb5Fuas1GQSeAtjnZWmZEQK"], [], []] + self.extra_args = [["-sporkkey=93QPD8M8SrVb4yL3E679sCGztzy1NRWYH3fs2wJQr2LMKnppFCJ"], [], []] def setup_network(self): self.disable_mocktime() diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 9a78b59f64142..540421a8d89dc 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -491,7 +491,7 @@ def set_ion_test_params(self, num_nodes, masterodes_count, extra_args, fast_dip3 # additional args self.extra_args = extra_args - self.extra_args += ["-sporkkey=cP4EKFyJsHT39LDqgdcB43Y3YXjNyjb5Fuas1GQSeAtjnZWmZEQK"] + self.extra_args += ["-sporkkey=93QPD8M8SrVb4yL3E679sCGztzy1NRWYH3fs2wJQr2LMKnppFCJ"] self.fast_dip3_enforcement = fast_dip3_enforcement if fast_dip3_enforcement: