diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 15e022ef..070ac276 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -34,6 +34,7 @@ public: nRPCPort = 28332; //bnProofOfWorkLimit = CBigNum(~uint256(0) >> 32); bnProofOfWorkLimit = CBigNum(~uint256(0) >> 1); + nTxBits = 0x207fffff; nSubsidyHalvingInterval = 210000; // Build the genesis block. Note that the output of the genesis coinbase cannot @@ -47,6 +48,7 @@ public: const char* pszTimestamp = "The Times 14/Jul/2013 Globo caught bribing Receita Federal employee to rob R$615M tax evasion documents."; CTransaction txNew; txNew.message = CScript() << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.nNonce = 1; genesis.vtx.push_back(txNew); genesis.hashPrevBlock = 0; genesis.hashMerkleRoot = genesis.BuildMerkleTree(); @@ -54,7 +56,7 @@ public: genesis.nTime = 1231006505; //genesis.nBits = 0x1d00ffff; genesis.nBits = 0x207fffff; - genesis.nNonce = 2; + genesis.nNonce = 0; hashGenesisBlock = genesis.GetHash(); printf("hashGenesisBlock %s\n", hashGenesisBlock.ToString().c_str()); @@ -148,6 +150,7 @@ public: pchMessageStart[3] = 0xda; nSubsidyHalvingInterval = 150; bnProofOfWorkLimit = CBigNum(~uint256(0) >> 1); + nTxBits = 0x207fffff; genesis.nTime = 1296688602; genesis.nBits = 0x207fffff; genesis.nNonce = 2; diff --git a/src/chainparams.h b/src/chainparams.h index 572712b5..3672f47a 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -54,6 +54,7 @@ public: const vector& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } const CBigNum& ProofOfWorkLimit() const { return bnProofOfWorkLimit; } + unsigned int txBits() const { return nTxBits; } int SubsidyHalvingInterval() const { return nSubsidyHalvingInterval; } virtual const CBlock& GenesisBlock() const = 0; virtual bool RequireRPCPassword() const { return true; } @@ -73,6 +74,7 @@ protected: int nDefaultPort; int nRPCPort; CBigNum bnProofOfWorkLimit; + unsigned int nTxBits; int nSubsidyHalvingInterval; string strDataDir; vector vSeeds; diff --git a/src/core.cpp b/src/core.cpp index c926d198..d55f445c 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -81,17 +81,16 @@ uint256 CTransaction::GetHash() const std::string CTransaction::ToString() const { std::string str; - str += strprintf("CTransaction(hash=%s, ver=%d, message.size=%"PRIszu", userID.size=%"PRIszu", pubKey.size=%"PRIszu")\n", + str += strprintf("CTransaction(hash=%s, ver=%d, message.size=%"PRIszu", userName.size=%"PRIszu", pubKey.size=%"PRIszu")\n", GetHash().ToString().substr(0,10).c_str(), nVersion, message.size(), - userID.size(), + userName.size(), pubKey.size()); if( message.size() ) { str += " message: " + message.ToString() + "\n"; } else { str += " userName: " + userName.ToString() + "\n"; - str += " userID: " + userID.ToString() + "\n"; str += " pubKey: " + pubKey.ToString() + "\n"; } return str; diff --git a/src/core.h b/src/core.h index 9955a7b5..98336317 100644 --- a/src/core.h +++ b/src/core.h @@ -182,8 +182,8 @@ public: int nVersion; CScript message; CScript userName; - CScript userID; CScript pubKey; + unsigned int nNonce; CTransaction() { @@ -196,8 +196,8 @@ public: nVersion = this->nVersion; READWRITE(message); READWRITE(userName); - READWRITE(userID); READWRITE(pubKey); + READWRITE(nNonce); ) void SetNull() @@ -205,20 +205,20 @@ public: nVersion = CTransaction::CURRENT_VERSION; message.clear(); userName.clear(); - userID.clear(); pubKey.clear(); + nNonce = 0; } bool IsNull() const { - return (message.empty() && userName.empty() && userID.empty() && pubKey.empty()); + return (message.empty() && userName.empty() && pubKey.empty()); } uint256 GetHash() const; bool IsSpamMessage() const { - return (!message.empty() && userID.empty() && pubKey.empty()); + return (!message.empty() && userName.empty() && pubKey.empty()); } friend bool operator==(const CTransaction& a, const CTransaction& b) @@ -226,7 +226,6 @@ public: return (a.nVersion == b.nVersion && a.message == b.message && a.userName == b.userName && - a.userID == b.userID && a.pubKey == b.pubKey); } @@ -548,6 +547,7 @@ public: // header static const int CURRENT_VERSION=2; int nVersion; + int nHeight; uint256 hashPrevBlock; uint256 hashMerkleRoot; unsigned int nTime; @@ -563,6 +563,7 @@ public: ( READWRITE(this->nVersion); nVersion = this->nVersion; + READWRITE(nHeight); READWRITE(hashPrevBlock); READWRITE(hashMerkleRoot); READWRITE(nTime); @@ -573,6 +574,7 @@ public: void SetNull() { nVersion = CBlockHeader::CURRENT_VERSION; + nHeight = 0; hashPrevBlock = 0; hashMerkleRoot = 0; nTime = 0; @@ -631,6 +633,7 @@ public: { CBlockHeader block; block.nVersion = nVersion; + block.nHeight = nHeight; block.hashPrevBlock = hashPrevBlock; block.hashMerkleRoot = hashMerkleRoot; block.nTime = nTime; diff --git a/src/main.cpp b/src/main.cpp index 4a398832..b6fee81c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -476,11 +476,6 @@ bool IsStandardTx(const CTransaction& tx, string& reason) return false; } - if (!IsFinalTx(tx)) { - reason = "non-final"; - return false; - } - // Extremely large transactions with lots of inputs can cost the network // almost as much to process as they cost the sender in fees, because // computing signature hashes is O(ninputs*txsize). Limiting transactions @@ -491,52 +486,6 @@ bool IsStandardTx(const CTransaction& tx, string& reason) return false; } - /* [MF] - BOOST_FOREACH(const CTxIn& txin, tx.vin) - { - // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG - // pay-to-script-hash, which is 3 ~80-byte signatures, 3 - // ~65-byte public keys, plus a few script ops. - if (txin.scriptSig.size() > 500) { - reason = "scriptsig-size"; - return false; - } - if (!txin.scriptSig.IsPushOnly()) { - reason = "scriptsig-not-pushonly"; - return false; - } - } - BOOST_FOREACH(const CTxOut& txout, tx.vout) { - if (!::IsStandard(txout.scriptPubKey)) { - reason = "scriptpubkey"; - return false; - } - if (txout.IsDust(CTransaction::nMinRelayTxFee)) { - reason = "dust"; - return false; - } - } - */ - return true; -} - -bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64 nBlockTime) -{ - /* [MF] - // Time based nLockTime implemented in 0.1.6 - if (tx.nLockTime == 0) - return true; - if (nBlockHeight == 0) - nBlockHeight = nBestHeight; - if (nBlockTime == 0) - nBlockTime = GetAdjustedTime(); - if ((int64)tx.nLockTime < ((int64)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime)) - return true; - BOOST_FOREACH(const CTxIn& txin, tx.vin) - if (!txin.IsFinal()) - return false; - - */ return true; } @@ -709,88 +658,32 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock) bool CheckTransaction(const CTransaction& tx, CValidationState &state) { - /* [MF] // Basic checks that don't depend on any context - if (tx.vin.empty()) - return state.DoS(10, error("CheckTransaction() : vin empty")); - if (tx.vout.empty()) - return state.DoS(10, error("CheckTransaction() : vout empty")); + if (tx.IsSpamMessage()) { + if (!tx.userName.empty()) + return state.DoS(10, error("CheckTransaction() : username not empty in spam message")); + if (!tx.pubKey.empty()) + return state.DoS(10, error("CheckTransaction() : pubKey empty not empty in spam message")); + if (tx.message.size() > MAX_SPAM_MSG_SIZE) + return state.DoS(100, error("CheckTransaction() : spam message too big")); + } else { + if (tx.userName.empty()) + return state.DoS(10, error("CheckTransaction() : username empty")); + if (tx.userName.size() > MAX_USERNAME_SIZE) + return state.DoS(100, error("CheckTransaction() : username too big")); + if (tx.pubKey.empty()) + return state.DoS(10, error("CheckTransaction() : pubKey empty")); + } // Size limits if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return state.DoS(100, error("CTransaction::CheckTransaction() : size limits failed")); + // Check proof of work matches claimed amount + if (!CheckProofOfWork(tx.GetHash(), Params().txBits()) ) + return state.DoS(50, error("CheckTransaction() : proof of work failed")); - // Check for negative or overflow output values - int64 nValueOut = 0; - BOOST_FOREACH(const CTxOut& txout, tx.vout) - { - if (txout.nValue < 0) - return state.DoS(100, error("CheckTransaction() : txout.nValue negative")); - if (txout.nValue > MAX_MONEY) - return state.DoS(100, error("CheckTransaction() : txout.nValue too high")); - nValueOut += txout.nValue; - if (!MoneyRange(nValueOut)) - return state.DoS(100, error("CTransaction::CheckTransaction() : txout total out of range")); - } - - // Check for duplicate inputs - set vInOutPoints; - BOOST_FOREACH(const CTxIn& txin, tx.vin) - { - if (vInOutPoints.count(txin.prevout)) - return state.DoS(100, error("CTransaction::CheckTransaction() : duplicate inputs")); - vInOutPoints.insert(txin.prevout); - } - - if (tx.IsCoinBase()) - { - if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100) - return state.DoS(100, error("CheckTransaction() : coinbase script size")); - } - else - { - BOOST_FOREACH(const CTxIn& txin, tx.vin) - if (txin.prevout.IsNull()) - return state.DoS(10, error("CheckTransaction() : prevout is null")); - } - */ return true; } -int64 GetMinFee(const CTransaction& tx, bool fAllowFree, enum GetMinFee_mode mode) -{ - /* - // Base fee is either nMinTxFee or nMinRelayTxFee - int64 nBaseFee = (mode == GMF_RELAY) ? tx.nMinRelayTxFee : tx.nMinTxFee; - - unsigned int nBytes = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee; - - if (fAllowFree) - { - // There is a free transaction area in blocks created by most miners, - // * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000 - // to be considered to fall into this category - // * If we are creating a transaction we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 17000 - // (= 10000) to be considered safe and assume they can likely make it into this section - if (nBytes < (mode == GMF_SEND ? (DEFAULT_BLOCK_PRIORITY_SIZE - 17000) : (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))) - nMinFee = 0; - } - - // To limit dust spam, require base fee if any output is less than 0.01 - if (nMinFee < nBaseFee) - { - BOOST_FOREACH(const CTxOut& txout, tx.vout) - if (txout.nValue < CENT) - nMinFee = nBaseFee; - } - - if (!MoneyRange(nMinFee)) - nMinFee = MAX_MONEY; - return nMinFee; - */ - return 0; -} - void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins) { LOCK(cs); @@ -817,12 +710,6 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr if (tx.IsSpamMessage()) return state.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx")); - /* - // To help v0.1.5 clients who would see it as a negative number - if ((int64)tx.nLockTime > std::numeric_limits::max()) - return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet"); -*/ - // Rather not work on nonstandard transactions (unless -testnet) string reason; if (!TestNet() && !IsStandardTx(tx, reason)) @@ -839,7 +726,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr // Check for conflicts with in-memory transactions CTransaction* ptxOld = NULL; - /* [MF] + /* for (unsigned int i = 0; i < tx.vin.size(); i++) { COutPoint outpoint = tx.vin[i].prevout; @@ -910,16 +797,8 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr // you should add code here to check that the transaction does a // reasonable number of ECDSA signature verifications. - int64 nFees = view.GetValueIn(tx)-GetValueOut(tx); unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - // Don't accept it if it can't get into a block - int64 txMinFee = GetMinFee(tx, true, GMF_RELAY); - if (fLimitFree && nFees < txMinFee) - return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d, - hash.ToString().c_str(), - nFees, txMinFee); - // Continuously rate-limit free transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. @@ -2341,11 +2220,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) return state.Invalid(error("AcceptBlock() : block's timestamp is too early")); - // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, block.vtx) - if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) - return state.DoS(10, error("AcceptBlock() : contains a non-final transaction")); - // Check that the block chain matches the known block chain up to a checkpoint if (!Checkpoints::CheckBlock(nHeight, hash)) return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight)); @@ -2353,25 +2227,13 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: if (block.nVersion < 2) { - if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) || - (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) - { - return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block")); - } + return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block")); } // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height if (block.nVersion >= 2) { - // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): - if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) || - (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100))) - { - CScript expect = CScript() << nHeight; - /* [MF] - if (!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) - return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase")); - */ - } + if( nHeight != block.nHeight ) + return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase")); } } @@ -4362,7 +4224,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) for (map::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) { CTransaction& tx = (*mi).second; - if (tx.IsSpamMessage() || !IsFinalTx(tx)) + if (tx.IsSpamMessage()) continue; COrphan* porphan = NULL; diff --git a/src/main.h b/src/main.h index 4c2d37ac..ae13a1a1 100644 --- a/src/main.h +++ b/src/main.h @@ -59,6 +59,10 @@ static const int fHaveUPnP = true; #else static const int fHaveUPnP = false; #endif +/** The maximum size for spam messages */ +static const unsigned int MAX_SPAM_MSG_SIZE = 140; +/** The maximum size for username */ +static const unsigned int MAX_USERNAME_SIZE = 16; extern CScript COINBASE_FLAGS; @@ -262,14 +266,6 @@ struct CDiskTxPos : public CDiskBlockPos -enum GetMinFee_mode -{ - GMF_RELAY, - GMF_SEND, -}; - -int64 GetMinFee(const CTransaction& tx, bool fAllowFree, enum GetMinFee_mode mode); - // // Check transaction inputs, and make sure any // pay-to-script-hash transactions are evaluating IsStandard scripts @@ -328,8 +324,6 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state); */ bool IsStandardTx(const CTransaction& tx, std::string& reason); -bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64 nBlockTime = 0); - /** Amount of bitcoins spent by the transaction. @return sum of all outputs (note: does not include fees) */ diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index af2ff258..401de7db 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -408,7 +408,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; - if (wtx.IsSpamMessage() || !IsFinalTx(wtx)) + if (wtx.IsSpamMessage()) continue; /* BOOST_FOREACH(const CTxOut& txout, wtx.vout) @@ -455,7 +455,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; - if (wtx.IsSpamMessage() || !IsFinalTx(wtx)) + if (wtx.IsSpamMessage()) continue; /* BOOST_FOREACH(const CTxOut& txout, wtx.vout) @@ -480,9 +480,6 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; - if (!IsFinalTx(wtx)) - continue; - int64 nReceived, nSent, nFee; wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee); @@ -841,7 +838,7 @@ Value ListReceived(const Array& params, bool fByAccounts) { const CWalletTx& wtx = (*it).second; - if (wtx.IsSpamMessage() || !IsFinalTx(wtx)) + if (wtx.IsSpamMessage()) continue; int nDepth = wtx.GetDepthInMainChain(); diff --git a/src/wallet.cpp b/src/wallet.cpp index f9f42248..ccd85478 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -971,29 +971,12 @@ int64 CWallet::GetBalance() const int64 CWallet::GetUnconfirmedBalance() const { int64 nTotal = 0; - { - LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) - { - const CWalletTx* pcoin = &(*it).second; - if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed()) - nTotal += pcoin->GetAvailableCredit(); - } - } return nTotal; } int64 CWallet::GetImmatureBalance() const { int64 nTotal = 0; - { - LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) - { - const CWalletTx* pcoin = &(*it).second; - nTotal += pcoin->GetImmatureCredit(); - } - } return nTotal; } @@ -1008,9 +991,6 @@ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed) const { const CWalletTx* pcoin = &(*it).second; - if (!IsFinalTx(*pcoin)) - continue; - if (fOnlyConfirmed && !pcoin->IsConfirmed()) continue; @@ -1705,7 +1685,7 @@ std::map CWallet::GetAddressBalances() { CWalletTx *pcoin = &walletEntry.second; - if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed()) + if (!pcoin->IsConfirmed()) continue; if (pcoin->IsSpamMessage() && pcoin->GetBlocksToMaturity() > 0) diff --git a/src/wallet.h b/src/wallet.h index c502bfc3..5a817d4a 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -660,9 +660,6 @@ public: bool IsConfirmed() const { - // Quick answer in most cases - if (!IsFinalTx(*this)) - return false; if (GetDepthInMainChain() >= 1) return true; if (!IsFromMe()) // using wtx's cached debit @@ -678,8 +675,6 @@ public: { const CMerkleTx* ptx = vWorkQueue[i]; - if (!IsFinalTx(*ptx)) - return false; if (ptx->GetDepthInMainChain() >= 1) continue; if (!pwallet->IsFromMe(*ptx))