diff --git a/src/amount.h b/src/amount.h index c0d37954c..62b966386 100644 --- a/src/amount.h +++ b/src/amount.h @@ -17,7 +17,7 @@ static const CAmount COIN = 100000000; static const CAmount CENT = 1000000; /** No amount larger than this (in satoshi) is valid */ -static const CAmount MAX_MONEY = 21000000 * COIN; +static const CAmount MAX_MONEY = 21000000000 * COIN; inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } /** Type-safe wrapper class to for fee rates diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 93c8c7aab..41b49bbd3 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -120,12 +120,12 @@ public: vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"); nDefaultPort = 8333; bnProofOfWorkLimit = ~uint256(0) >> 1; - nSubsidyHalvingInterval = 210000; + nSubsidyHalvingInterval = 2100000; nEnforceBlockUpgradeMajority = 750; nRejectBlockOutdatedMajority = 950; nToCheckBlockUpgradeMajority = 1000; nMinerThreads = 2; - nTargetTimespan = 30 * 60;//14 * 24 * 60 * 60; // two weeks + nTargetTimespan = 30 * 60 * 10;//14 * 24 * 60 * 60; // two weeks nTargetSpacing = 30; /** @@ -170,10 +170,10 @@ public: }*/ hashGenesisBlock = genesis.GetHash(); - printf("%s\n", hashGenesisBlock.GetHex().c_str()); + //printf("%s\n", hashGenesisBlock.GetHex().c_str()); //assert(hashGenesisBlock == uint256("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")); assert(hashGenesisBlock == uint256("0x008c55867210a8154af697b7776c6b6cdb26972381eac9f84d18a491374464a3")); - printf("%s\n", genesis.hashMerkleRoot.GetHex().c_str()); + //printf("%s\n", genesis.hashMerkleRoot.GetHex().c_str()); //assert(genesis.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); assert(genesis.hashMerkleRoot == uint256("0xa7d51d407092059a2beeffab22e65d6176cfb3c33b93515109480aa7c81c9141")); diff --git a/src/coins.cpp b/src/coins.cpp index c2e802c95..cf290a31e 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -6,6 +6,8 @@ #include "random.h" +#include "util.h" + #include /** @@ -36,6 +38,7 @@ bool CCoins::Spend(const COutPoint &out, CTxInUndo &undo) { return false; if (vout[out.n].IsNull()) return false; + LogPrintf("In CCoins::Spend for output %d in transaction %s\n", out.n, out.hash.GetHex().c_str()); undo = CTxInUndo(vout[out.n]); vout[out.n].SetNull(); Cleanup(); diff --git a/src/main.cpp b/src/main.cpp index 4160e4b78..060011183 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -616,11 +616,76 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) +bool DecodeNCCScript(const CScript& scriptIn, int& op, std::vector >& vvchParams) +{ + CScript::const_iterator pc = scriptIn.begin(); + return DecodeNCCScript(scriptIn, op, vvchParams, pc); +} + +bool DecodeNCCScript(const CScript& scriptIn, int& op, std::vector >& vvchParams, CScript::const_iterator& pc) +{ + opcodetype opcode; + if (!scriptIn.GetOp(pc, opcode)) + { + return false; + } + if (opcode != OP_CLAIM_NAME) + { + return false; + } + + op = opcode; + + std::vector vchName; + std::vector vchValue; + + // The correct format is: + // OP_CLAIM_NAME vchName vchValue OP_DROP2 OP_DROP pubkeyscript + // All others are invalid. + + if (!scriptIn.GetOp(pc, opcode, vchName) || opcode < 0 || opcode > OP_PUSHDATA4) + { + return false; + } + if (!scriptIn.GetOp(pc, opcode, vchValue) || opcode < 0 || opcode > OP_PUSHDATA4) + { + return false; + } + if (!scriptIn.GetOp(pc, opcode) || opcode != OP_2DROP) + { + return false; + } + if (!scriptIn.GetOp(pc, opcode) || opcode != OP_DROP) + { + return false; + } + + vvchParams.push_back(vchName); + vvchParams.push_back(vchValue); + + return true; +} + +CScript StripNCCScriptPrefix(const CScript& scriptIn) +{ + int op; + std::vector > vvchParams; + CScript::const_iterator pc = scriptIn.begin(); + + if (!DecodeNCCScript(scriptIn, op, vvchParams, pc)) + { + return scriptIn; + } + + return CScript(pc, scriptIn.end()); +} + bool IsStandardTx(const CTransaction& tx, string& reason) { AssertLockHeld(cs_main); + // TODO: We may have a different version here if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) { reason = "version"; return false; @@ -680,7 +745,10 @@ bool IsStandardTx(const CTransaction& tx, string& reason) unsigned int nDataOut = 0; txnouttype whichType; BOOST_FOREACH(const CTxOut& txout, tx.vout) { - if (!::IsStandard(txout.scriptPubKey, whichType)) { + + const CScript& scriptPubKey = StripNCCScriptPrefix(txout.scriptPubKey); + + if (!::IsStandard(scriptPubKey, whichType)) { reason = "scriptpubkey"; return false; } @@ -744,7 +812,8 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) vector > vSolutions; txnouttype whichType; // get the scriptPubKey corresponding to this input: - const CScript& prevScript = prev.scriptPubKey; + const CScript& prevScript = StripNCCScriptPrefix(prev.scriptPubKey); + if (!Solver(prevScript, whichType, vSolutions)) return false; int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions); @@ -814,8 +883,9 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in for (unsigned int i = 0; i < tx.vin.size(); i++) { const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]); - if (prevout.scriptPubKey.IsPayToScriptHash()) - nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig); + const CScript& scriptPubKey = StripNCCScriptPrefix(prevout.scriptPubKey); + if (scriptPubKey.IsPayToScriptHash()) + nSigOps += scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig); } return nSigOps; } @@ -1712,6 +1782,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); + // TODO: This seems like a good place to actually change the + // TODO: tree of NCCs and make the CUndo vector for those changes. + vPos.push_back(std::make_pair(tx.GetHash(), pos)); pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); } @@ -2516,6 +2589,9 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn } } + // TODO: This looks like a good place to check the "merkle" root of the + // TODO: NCC tree that will result from applying this block + return true; } diff --git a/src/main.h b/src/main.h index 8f0378647..9161051dd 100644 --- a/src/main.h +++ b/src/main.h @@ -304,6 +304,11 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason); bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64_t nBlockTime = 0); +bool DecodeNCCScript(const CScript& scriptIn, int& op, std::vector >& vvchParams); +bool DecodeNCCScript(const CScript& scriptIn, int& op, std::vector >& vvchParams, CScript::const_iterator& pc); +CScript StripNCCScriptPrefix(const CScript& scriptIn); + + /** Undo information for a CBlock */ class CBlockUndo { diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index e43eee155..39feade73 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -310,6 +310,74 @@ Value getaddressesbyaccount(const Array& params, bool fHelp) return ret; } +void ClaimName(const std::vector vchName, const std::vector vchValue, CAmount nAmount, CWalletTx& wtxNew) +{ + // Check amount + if (nAmount <= 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); + + if (nAmount > pwalletMain->GetBalance()) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); + + string strError; + if (pwalletMain->IsLocked()) + { + strError = "Error: Wallet locked, unable to create transaction!"; + LogPrintf("SendMoney() : %s", strError); + throw JSONRPCError(RPC_WALLET_ERROR, strError); + } + + //Get new address + CPubKey newKey; + if (!pwalletMain->GetKeyFromPool(newKey)) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + + CScript scriptPubKey = GetScriptForDestination(CTxDestination(newKey.GetID())); + CScript claimScript = CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP << scriptPubKey; + + CReserveKey reservekey(pwalletMain); + CAmount nFeeRequired; + if (!pwalletMain->CreateTransaction(claimScript, nAmount, wtxNew, reservekey, nFeeRequired, strError)) + { + if (nAmount + nFeeRequired > pwalletMain->GetBalance()) + strError = strprintf("Error: This transaction requires a transaction fee of at least %s because if its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); + LogPrintf("ClaimName() : %s\n", strError); + throw JSONRPCError(RPC_WALLET_ERROR, strError); + } + if (!pwalletMain->CommitTransaction(wtxNew, reservekey)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might hapen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); +} + +Value claimname(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 3) + throw runtime_error( + "claimname \"name\" \"value\" amount\n" + "\nCreate a transaction which issues a claim assigning a value to a name. The claim will be authoritative if the transaction amount is greater than the transaction amount of all other unspent transactions which issue a claim over the same name, and it will remain authoritative as long as it remains unspent. The amount is a real and is rounded to the nearest 0.00000001\n" + + HelpRequiringPassphrase() + + "\nArguments:\n" + "1. \"name\" (string, required) The name to be assigned the value.\n" + "2. \"value\" (string, required) The value to assign to the name.\n" + "3. \"amount\n (numeric, required) The amount in ncc to send. eg 0.1\n" + "\nResult:\n" + "\"transactionid\" (string) The transaction id.\n" + ); + string sName = params[0].get_str(); + string sValue = params[1].get_str(); + std::vector vchName (sName.begin(), sName.end()); + std::vector vchValue (sValue.begin(), sValue.end()); + CAmount nAmount = AmountFromValue(params[2]); + + CWalletTx wtx; + + EnsureWalletIsUnlocked(); + + ClaimName(vchName, vchValue, nAmount, wtx); + + return wtx.GetHash().GetHex(); +} + + void SendMoney(const CTxDestination &address, CAmount nValue, CWalletTx& wtxNew) { // Check amount diff --git a/src/script/script.h b/src/script/script.h index 9c22cb908..5f625abce 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -29,6 +29,7 @@ enum opcodetype // push value OP_0 = 0x00, OP_FALSE = OP_0, + OP_CLAIM_NAME = OP_0, OP_PUSHDATA1 = 0x4c, OP_PUSHDATA2 = 0x4d, OP_PUSHDATA4 = 0x4e, diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp index 8f70f18c7..bd23255e4 100644 --- a/src/test/Checkpoints_tests.cpp +++ b/src/test/Checkpoints_tests.cpp @@ -18,21 +18,21 @@ BOOST_AUTO_TEST_SUITE(Checkpoints_tests) BOOST_AUTO_TEST_CASE(sanity) { - uint256 p11111 = uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"); - uint256 p134444 = uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"); - BOOST_CHECK(Checkpoints::CheckBlock(11111, p11111)); - BOOST_CHECK(Checkpoints::CheckBlock(134444, p134444)); +// uint256 p11111 = uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"); +// uint256 p134444 = uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"); +// BOOST_CHECK(Checkpoints::CheckBlock(11111, p11111)); +// BOOST_CHECK(Checkpoints::CheckBlock(134444, p134444)); // Wrong hashes at checkpoints should fail: - BOOST_CHECK(!Checkpoints::CheckBlock(11111, p134444)); - BOOST_CHECK(!Checkpoints::CheckBlock(134444, p11111)); +// BOOST_CHECK(!Checkpoints::CheckBlock(11111, p134444)); +// BOOST_CHECK(!Checkpoints::CheckBlock(134444, p11111)); // ... but any hash not at a checkpoint should succeed: - BOOST_CHECK(Checkpoints::CheckBlock(11111+1, p134444)); - BOOST_CHECK(Checkpoints::CheckBlock(134444+1, p11111)); +// BOOST_CHECK(Checkpoints::CheckBlock(11111+1, p134444)); +// BOOST_CHECK(Checkpoints::CheckBlock(134444+1, p11111)); - BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 134444); +// BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 134444); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index bf57dd81d..af9bf8c6f 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -18,7 +18,8 @@ BOOST_AUTO_TEST_CASE(subsidy_limit_test) nSum += nSubsidy * 1000; BOOST_CHECK(MoneyRange(nSum)); } - BOOST_CHECK(nSum == 2099999997690000ULL); + //BOOST_CHECK(nSum == 2099999997690000ULL); + BOOST_CHECK(nSum == 20781250000000000LL); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 53c2e7b26..951b7b3ce 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -12,7 +12,7 @@ BOOST_AUTO_TEST_SUITE(miner_tests) -static +/*static struct { unsigned char extranonce; unsigned int nonce; @@ -45,6 +45,41 @@ struct { {1, 0x3141c7c1}, {1, 0xb3b595f4}, {1, 0x735abf08}, {5, 0x623bfbce}, {2, 0xd351e722}, {1, 0xf4ca48c9}, {1, 0x5b19c670}, {1, 0xa164bf0e}, {2, 0xbbbeb305}, {2, 0xfe1c810a}, +};*/ + +static +struct { + unsigned char extranonce; + unsigned int nonce; +} blockinfo[] = { + {4, 0x00000002}, {2, 0x00000002}, {1, 0x00000000}, {1, 0x00000001}, //0 + {2, 0x00000001}, {2, 0x00000002}, {1, 0x00000000}, {2, 0x0000000b}, //4 + {2, 0x00000000}, {1, 0x00000000}, {1, 0x00000000}, {2, 0x00000001}, //8 + {2, 0x00000000}, {1, 0x00000000}, {2, 0x00000000}, {2, 0x00000001}, //12 + {1, 0x00000000}, {2, 0x00000004}, {1, 0x00000000}, {1, 0x00000000}, //16 + {3, 0x00000002}, {2, 0x00000000}, {2, 0x00000000}, {1, 0x00000000}, //20 + {2, 0x00000000}, {1, 0x00000002}, {2, 0x00000000}, {2, 0x00000000}, //24 + {2, 0x00000000}, {2, 0x00000001}, {2, 0x00000000}, {2, 0x00000000}, //28 + {1, 0x00000000}, {2, 0x00000001}, {2, 0x00000000}, {1, 0x00000000}, //32 + {2, 0x00000001}, {1, 0x00000000}, {2, 0x00000001}, {1, 0x00000000}, //36 + {1, 0x00000001}, {3, 0x00000000}, {2, 0x00000000}, {5, 0x00000002}, //40 + {1, 0x00000001}, {5, 0x00000000}, {1, 0x00000005}, {1, 0x00000000}, //44 + {1, 0x00000000}, {2, 0x00000002}, {1, 0x00000002}, {1, 0x00000000}, //48 + {1, 0x00000000}, {1, 0x00000000}, {5, 0x00000001}, {5, 0x00000000}, //52 + {1, 0x00000000}, {1, 0x00000000}, {6, 0x00000000}, {2, 0x00000001}, //56 + {2, 0x00000000}, {1, 0x00000000}, {1, 0x00000001}, {1, 0x00000002}, //60 + {2, 0x00000001}, {2, 0x00000000}, {1, 0x00000003}, {1, 0x00000001}, //64 + {1, 0x00000000}, {5, 0x00000000}, {5, 0x00000002}, {1, 0x00000001}, //68 + {1, 0x00000001}, {2, 0x00000000}, {2, 0x00000001}, {1, 0x00000003}, //72 + {2, 0x00000002}, {1, 0x00000000}, {2, 0x00000000}, {2, 0x00000006}, //76 + {1, 0x00000000}, {1, 0x00000000}, {1, 0x00000001}, {5, 0x00000000}, //80 + {1, 0x00000001}, {1, 0x00000001}, {1, 0x00000000}, {1, 0x00000002}, //84 + {1, 0x00000000}, {1, 0x00000000}, {1, 0x00000002}, {2, 0x00000001}, //88 + {0, 0x00000003}, {1, 0x00000004}, {2, 0x00000000}, {2, 0x00000001}, //92 + {2, 0x00000000}, {1, 0x00000002}, {1, 0x00000000}, {1, 0x00000002}, //96 + {1, 0x00000000}, {1, 0x00000003}, {1, 0x00000000}, {5, 0x00000000}, //100 + {2, 0x00000000}, {1, 0x00000000}, {1, 0x00000001}, {1, 0x00000001}, //104 + {2, 0x00000000}, {2, 0x00000002}, //108 }; // NOTE: These tests rely on CreateNewBlock doing its own self-validation! @@ -80,6 +115,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) txFirst.push_back(new CTransaction(pblock->vtx[0])); pblock->hashMerkleRoot = pblock->BuildMerkleTree(); pblock->nNonce = blockinfo[i].nonce; + /*bool fFound = false; + for (int j = 0; !fFound; j++) + { + pblock->nNonce = j; + if (CheckProofOfWork(pblock->GetHash(), pblock->nBits)) + { + fFound = true; + std::cout << "Block number: " << i << std::endl; + std::cout << "Nonce: " << std::hex << pblock->nNonce << std::dec << std::endl; + } + }*/ CValidationState state; BOOST_CHECK(ProcessNewBlock(state, NULL, pblock)); BOOST_CHECK(state.IsValid()); @@ -198,6 +244,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) delete pblocktemplate; mempool.clear(); +/* This has been removed because we don't have that many blocks in the active chain yet. + It should be returned when we do. // subsidy changing int nHeight = chainActive.Height(); chainActive.Tip()->nHeight = 209999; @@ -207,6 +255,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = nHeight; +*/ // non-final txs in mempool SetMockTime(chainActive.Tip()->GetMedianTimePast()+1); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index e939e8997..544b2682c 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -373,6 +373,18 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) t.vout[0].scriptPubKey = CScript() << OP_RETURN; t.vout[1].scriptPubKey = CScript() << OP_RETURN; BOOST_CHECK(!IsStandardTx(t, reason)); + + // NCC transactions + + t.vout.resize(1); + string sName = "testname"; + string sValue = "testvalue"; + std::vector vchName (sName.begin(), sName.end()); + std::vector vchValue (sValue.begin(), sValue.end()); + CScript scriptPubKey = CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP; + t.vout[0].scriptPubKey = scriptPubKey + GetScriptForDestination(key.GetPubKey().GetID()); + t.vout[0].nValue = 10*COIN; + BOOST_CHECK(IsStandardTx(t, reason)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/txdb.cpp b/src/txdb.cpp index 29ef35037..356e829d7 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -15,10 +15,14 @@ using namespace std; void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) { - if (coins.IsPruned()) + if (coins.IsPruned()) { + LogPrintf("BatchWriteCoins erasing %s\n", hash.GetHex().c_str()); batch.Erase(make_pair('c', hash)); - else + } + else { + LogPrintf("BatchWriteCoins writing %s\n", hash.GetHex().c_str()); batch.Write(make_pair('c', hash), coins); + } } void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {