From a44e98654b87344200150148ad30161b1391de67 Mon Sep 17 00:00:00 2001 From: Vincent Durham Date: Wed, 11 May 2011 05:12:41 -0400 Subject: [PATCH] use pertxout for name operations --- README.md | 14 ++----- TODO-namecoin | 10 +++-- src/namecoin.cpp | 101 +++++++++++++++++++---------------------------- 3 files changed, 51 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index cd73c32e9..3068aec7e 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Please read DESIGN-namecoind.md before proceeding. BUILDING ====================== -Follow the bitcoin build instructions. Use "makefile" - it will generate namecoind. Usage is similar to bitcoind. There are only RPC calls for the new operations. A GUI is on the roadmap. +Building is only supported on Linux for now. Follow the bitcoin build instructions. Use "makefile.unix" - it will generate namecoind. Usage is similar to bitcoind, plus new RPC calls for the new operations. A GUI is on the roadmap. RUNNING ====================== @@ -63,17 +63,9 @@ VALUES Values for names in the d/ namespace are JSON encoded. The simplest value is of this form: - {'map': {'': '10.0.0.1'}} + {"map": {"": "10.0.0.1"}} -which maps all hosts in the domain example.bit to one IP address. But you can also delegate to your DNS servers: - - {'map': {'': {'ns': ['10.0.0.1', '10.0.0.2']}}} - -or even do a translation step before delegation: - - {'map': {'': {'translate': 'bitcoin.org', 'ns': ['10.0.0.1', '10.0.0.2']}}} - -in which case, foo.example.bit will be translated to foo.bitcoin.org before it is sent to your DNS servers. +A [full specification](http://dot-bit.org/Domain_names) is in progress. DNS conduits ============= diff --git a/TODO-namecoin b/TODO-namecoin index 24fd5a81c..5dae1afb7 100644 --- a/TODO-namecoin +++ b/TODO-namecoin @@ -5,11 +5,15 @@ * other conflicts: update on expired name, firstupdate on expired name_new * d7cc9e949d invalid number of args * blockexplorer -* resolver -* IsMine hook to ensure modified clients don't spend namecoins by mistake as regular coins -* listtransactions decode +* IsMine hook to ensure modified clients don't spend namecoins by mistake as regular coins in case of future changes to IsMine +* listtransactions improved decode * auto-send firstupdate after 6 blocks with persistent name/rand * review threading * sideloading resolver library * reference DNS server * cross-mining + +Bugs + +* CWalletTx::GetAmounts nFee is off by 0.01 for name txs because IsMine is false on the name output +* Reports of crashes, bdb was mentioned diff --git a/src/namecoin.cpp b/src/namecoin.cpp index e12b0f075..b44381a15 100644 --- a/src/namecoin.cpp +++ b/src/namecoin.cpp @@ -19,7 +19,7 @@ extern int64 AmountFromValue(const Value& value); extern Object JSONRPCError(int code, const string& message); template void ConvertTo(Value& value); -extern bool SelectCoins(int64 nTargetValue, set& setCoinsRet); +extern bool SelectCoins(int64 nTargetValue, set >& setCoinsRet, int64& nValueRet); static const int NAMECOIN_TX_VERSION = 0x7100; static const int64 MIN_AMOUNT = CENT; @@ -238,39 +238,25 @@ bool CreateTransactionWithInputTx(const vector >& vecSend, foreach (const PAIRTYPE(CScript, int64)& s, vecSend) wtxNew.vout.push_back(CTxOut(s.second, s.first)); - int64 nWtxinCredit; - - if (wtxIn.fSpent) - { - // non-name outputs have been spent, only grab name output value - nWtxinCredit = wtxIn.vout[nTxOut].nValue; - printf("input credit / spent = %d\n", nWtxinCredit); - } - else - { - // no part of wtxIn was spent, grab the entire coin - nWtxinCredit = wtxIn.GetCredit(); - printf("input credit / non-spent = %d\n", nWtxinCredit); - } + int64 nWtxinCredit = wtxIn.vout[nTxOut].nValue; // Choose coins to use - set setCoins; - if (!SelectCoins(nTotalValue - nWtxinCredit, setCoins)) - return false; + set > setCoins; int64 nValueIn = 0; + if (!SelectCoins(nTotalValue - nWtxinCredit, setCoins, nValueIn)) + return false; - vector vecCoins(setCoins.begin(), setCoins.end()); + vector > + vecCoins(setCoins.begin(), setCoins.end()); - foreach(CWalletTx* pcoin, vecCoins) + foreach(PAIRTYPE(CWalletTx*, unsigned int)& coin, vecCoins) { - // wtxIn non-name outputs might have been spent - int64 nCredit = pcoin->GetCredit(); - nValueIn += nCredit; - dPriority += (double)nCredit * pcoin->GetDepthInMainChain(); + int64 nCredit = coin.first->vout[coin.second].nValue; + dPriority += (double)nCredit * coin.first->GetDepthInMainChain(); } // Input tx always at first position - vecCoins.insert(vecCoins.begin(), &wtxIn); + vecCoins.insert(vecCoins.begin(), make_pair(&wtxIn, nTxOut)); nValueIn += nWtxinCredit; dPriority += (double)nWtxinCredit * wtxIn.GetDepthInMainChain(); @@ -305,37 +291,24 @@ bool CreateTransactionWithInputTx(const vector >& vecSend, reservekey.ReturnKey(); // Fill vin - foreach(CWalletTx* pcoin, vecCoins) - for (int nOut = 0; nOut < pcoin->vout.size(); nOut++) - { - // three cases: - // * this is wtxIn name output, which can only be spent by this function - grab it - // * this is a wtxIn non-name output and the non-name part of the coin was already spent - skip - // * this is not wtxIn - we already checked it wasn't spent, grab it - if (pcoin == &wtxIn && nOut == nTxOut) - { - if (pcoin->vout[nOut].IsMine()) - throw runtime_error("CreateTransactionWithInputTx() : wtxIn[nTxOut] already mine"); - wtxNew.vin.push_back(CTxIn(pcoin->GetHash(), nOut)); - } - else if (!pcoin->fSpent && pcoin->vout[nOut].IsMine()) - wtxNew.vin.push_back(CTxIn(pcoin->GetHash(), nOut)); - } + foreach(PAIRTYPE(CWalletTx*, unsigned int)& coin, vecCoins) + wtxNew.vin.push_back(CTxIn(coin.first->GetHash(), coin.second)); // Sign int nIn = 0; - foreach(CWalletTx* pcoin, vecCoins) - for (int nOut = 0; nOut < pcoin->vout.size(); nOut++) + foreach(PAIRTYPE(CWalletTx*, unsigned int)& coin, vecCoins) + { + if (coin.first == &wtxIn && coin.second == nTxOut) { - if (pcoin == &wtxIn && nOut == nTxOut) - { - if (!SignNameSignature(*pcoin, wtxNew, nIn++)) - throw runtime_error("could not sign name coin output"); - } - else if (!pcoin->fSpent && pcoin->vout[nOut].IsMine()) - if (!SignSignature(*pcoin, wtxNew, nIn++)) - return false; + if (!SignNameSignature(*coin.first, wtxNew, nIn++)) + throw runtime_error("could not sign name coin output"); } + else + { + if (!SignSignature(*coin.first, wtxNew, nIn++)) + return false; + } + } // Limit size unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK); @@ -801,7 +774,7 @@ Value name_update(const Array& params, bool fHelp) Value name_new(const Array& params, bool fHelp) { - if (fHelp) + if (fHelp || params.size() != 1) throw runtime_error( "name_new \n" ); @@ -845,15 +818,20 @@ void UnspendInputs(CWalletTx& wtx) continue; } CWalletTx& prev = mapWallet[txin.prevout.hash]; + int nOut = txin.prevout.n; - setCoins.insert(&prev); - } - foreach(CWalletTx* pcoin, setCoins) - { - printf("UnspendInputs(): %s spent %d\n", pcoin->GetHash().ToString().c_str(), pcoin->fSpent); - pcoin->fSpent = false; - pcoin->WriteToDisk(); - vWalletUpdated.push_back(pcoin->GetHash()); + printf("UnspendInputs(): %s:%d spent %d\n", prev.GetHash().ToString().c_str(), nOut, prev.IsSpent(nOut)); + + if (nOut >= prev.vout.size()) + throw runtime_error("CWalletTx::MarkSpent() : nOut out of range"); + prev.vfSpent.resize(prev.vout.size()); + if (prev.vfSpent[nOut]) + { + prev.vfSpent[nOut] = false; + prev.fAvailableCreditCached = false; + prev.WriteToDisk(); + } + vWalletUpdated.push_back(prev.GetHash()); } } @@ -894,6 +872,9 @@ Value deletetransaction(const Array& params, bool fHelp) Value name_clean(const Array& params, bool fHelp) { + if (fHelp || params.size()) + throw runtime_error("name_clean\nClean unsatisfiable transactions from the wallet - including name_update on an already taken name\n"); + CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_mapWallet) {