Skip to content
This repository
69  DESIGN-namecoin.md
Source Rendered
... ...
@@ -0,0 +1,69 @@
  1
+# Name Coin Design
  2
+
  3
+## Key Operations
  4
+
  5
+Key operations are performed by transactions with version 0x9900 - 0x99ff
  6
+
  7
+* name\_new(hash(rand, name), value)
  8
+* name\_firstupdate(name, rand, value)
  9
+* name\_update(name, value)
  10
+
  11
+The last is a normal bitcoin like transaction that does not affect the name.
  12
+
  13
+## Method
  14
+
  15
+A transaction can have a name operation associated with it.  An operation can reserve (name\_new), initialize (name\_firstupdate) or update (name\_update) a name/value pair.
  16
+
  17
+The name\_firstupdate transaction has a network fee.  The network fees represents namecoins (NC) that are destroyed.  This is in addition to the bitcoin-like miner transaction fees.
  18
+
  19
+## Key Operations Detail
  20
+
  21
+* The pubkey script starts with the following constants (OP\_N or OP\_PUSHDATA), followed by a OP_DROP, OP_2DROP or OP_NOP:
  22
+  * name\_new: [NAME\_NEW, hash(rand, name), value]
  23
+  * name\_firstupdate: [NAME\_FIRSTUPDATE, name, [newtx\_hash,] rand, value]
  24
+  * name\_update: [NAME\_UPDATE, name, value]
  25
+* name\_firstupdate will be accepted at or after 12 blocks of the matching name\_new
  26
+* in case of a collision, the first non-ignore name\_new wins
  27
+* new names are valid after name\_firstupdate
  28
+* name is a byte array of max length 255
  29
+* value is a byte array of max length 1023
  30
+* The transaction can only be inserted into a block where the current network fee is less than the network fee output of the transaction
  31
+* a name expires 12000 blocks from the last operation
  32
+
  33
+## Network fees
  34
+
  35
+The purpose of the network fees is to slow down the initial gold-rush.
  36
+
  37
+* Network fees start out at 50 NC per operation at the genesis block
  38
+* Every block, the network fees decreases based on this algorithm, in 1e-8 NC:
  39
+  * res = 500000000 >> floor(nBlock / 8192)
  40
+  * res = res - (res >> 14)*(nBlock % 8192)
  41
+* nBlock is zero at the genesis block
  42
+* This is a decrease of 50% every 8192 blocks (about two months)
  43
+* As 50 NC are generated per block, the maximum number of registrations in the first 8192 blocks is therefore 2/3 of 8192, which is 5461
  44
+* Difficulty starts at 512
  45
+
  46
+## Validation
  47
+
  48
+A name operation transaction can be inserted in a block if the following validations pass:
  49
+
  50
+* normal bitcoin validations pass
  51
+* if the transaction version does not indicate namecoin, no inputs can be namecoin outputs (i.e. have namecoin transaction id and have a namecoin script)
  52
+* if the transaction version does not indicate namecoin, terminate with success
  53
+* one of the outputs is >= the network fee of the block and has the script: OP\_RETURN (i.e. cannot be used as input, coins are lost)
  54
+* if this is an name\_update, exactly one of the inputs is an name\_update or name\_firstupdate on this name and the difference in block numbers is at most 12000.  Also, no other inputs are name operations.
  55
+* if this is a name\_firstupdate, exactly one of the inputs is a name\_new with block difference at least 12 but not more than 12000. No other inputs are name operations.
  56
+* if this is a name\_new, none of the inputs is a name operation.
  57
+* a name\_firstupdate must be on a name never seen or that has expired
  58
+
  59
+## Payment of network fee
  60
+
  61
+One of the outputs of a name\_firstupdate or name\_update transaction is lost (cannot be an input to a further transaction and has a script of exactly "OP_RETURN")
  62
+
  63
+## Applications
  64
+
  65
+The name is normally interpreted as a UTF-8 string composed of several slash-separated substrings.  The first element is a application specifier.
  66
+
  67
+For DNS, the first element shall be "d" and there are exactly two elements.  Mapping into the .bit domain is simply: d/xyz => xyz.bit .  The value is interpreted as a zone specification.  It is recommended that names stop serving 1000 blocks before expiration, as a signal to prevent a forgetful registrant from losing the domain immediately after it expires.
  68
+
  69
+For personal public name, the first element shall be "p" and there are exactly two elements.  The value is interpreted as a json encoded hash.  The "key" element of the cash contains PGP encoded keys.
16  README-bitcoin.md
Source Rendered
... ...
@@ -0,0 +1,16 @@
  1
+Bitcoin integration/staging tree
  2
+
  3
+Development process
  4
+===================
  5
+
  6
+Developers work in their own trees, then submit pull requests when they think their feature or bug fix is ready.
  7
+
  8
+If it is a simple/trivial/non-controversial change, then one of the bitcoin development team members simply pulls it.
  9
+
  10
+If it is a more complicated or potentially controversial change, then the patch submitter will be asked to start a discussion (if they haven't already) on the development forums:  http://www.bitcoin.org/smf/index.php?board=6.0
  11
+The patch will be accepted if there is broad consensus that it is a good thing.  Developers should expect to rework and resubmit patches if they don't match the project's coding conventions (see coding.txt) or are controversial.
  12
+
  13
+The master branch is regularly built and tested (by who? need people willing to be quality assurance testers), and periodically pushed to the subversion repo to become the official, stable, released bitcoin.
  14
+
  15
+
  16
+Feature branches are created when there are major new features being worked on by several people.
63  README.md
Source Rendered
... ...
@@ -1,16 +1,61 @@
1  
-Bitcoin integration/staging tree
2  
-
3  
-Development process
  1
+Namecoin
4 2
 ===================
5 3
 
6  
-Developers work in their own trees, then submit pull requests when they think their feature or bug fix is ready.
  4
+Namecoin is a peer to peer naming system based on bitcoin.  It is a secure and cnesorship reistant replacement for DNS.
  5
+
  6
+Ownership of a name is based on ownership of a coin, which is in turn based on public key cryptography.  The namecoin network reaches consensus every few minutes as to which names have been reserved or updated.
  7
+
  8
+It is envisioned that the .bit domain be used for gluing namecoin domain names into the DNS.  This can be done close to the user or even by the user.
  9
+
  10
+Technical
  11
+=====================
  12
+
  13
+The Bitcoin protocol is augmented with namecoin operations, to reserve, register and update names.  In addition to DNS like entries, arbitrary name/value pairs are allowed and multiple namespaces will be available.  This will include a personal handle namespace mapping handles to public keys and personal address data.
  14
+
  15
+The protocol differences from bitcoin include:
  16
+
  17
+* Different blockchain, port, IRC bootstrap and message header
  18
+* New transaction types: new, first-update, update
  19
+* Validation on the new transaction types
  20
+* RPC calls for managing names
  21
+* Network fees to slow down the initial rush
  22
+
  23
+Please read DESIGN-namecoind.md before proceeding.
  24
+
  25
+BUILDING
  26
+======================
  27
+
  28
+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.
7 29
 
8  
-If it is a simple/trivial/non-controversial change, then one of the bitcoin development team members simply pulls it.
  30
+RUNNING
  31
+======================
9 32
 
10  
-If it is a more complicated or potentially controversial change, then the patch submitter will be asked to start a discussion (if they haven't already) on the development forums:  http://www.bitcoin.org/smf/index.php?board=6.0
11  
-The patch will be accepted if there is broad consensus that it is a good thing.  Developers should expect to rework and resubmit patches if they don't match the project's coding conventions (see coding.txt) or are controversial.
  33
+You can acquire namecoins in the usual bitcoin way, by mining or by reciving some from others.  After you have acquired some namecoins, use:
12 34
 
13  
-The master branch is regularly built and tested (by who? need people willing to be quality assurance testers), and periodically pushed to the subversion repo to become the official, stable, released bitcoin.
  35
+`namecoind name_new d/<name>`
14 36
 
  37
+This will reserve a name but not make it visible yet.  Make a note of the short hex number.  You will need it for the next step.  (Do not shut down namecoind or you will also have to supply the longer hex code below.)  Wait about 12 blocks, then issue:
  38
+
  39
+`namecoind name_firstupdate d/<name> <rand> <value>`
  40
+
  41
+`<rand>` is the short hex number from the previous step.  This step will make the name visible to all.
  42
+
  43
+after the first update, you can do more updates with:
  44
+
  45
+`namecoind name_update d/<name> <value>`
  46
+
  47
+dump your list of names:
  48
+
  49
+`namecoind name_list`
  50
+
  51
+dump the global list:
  52
+
  53
+`namecoind name_scan`
  54
+
  55
+ROADMAP
  56
+===================
15 57
 
16  
-Feature branches are created when there are major new features being worked on by several people.
  58
+* DNS zone conduit to allow normal DNS server to serve the .bit domain
  59
+* Tor naming resolution conduit
  60
+* Firefox/chrome/... plugins
  61
+* GUI
8  TODO-namecoin
... ...
@@ -0,0 +1,8 @@
  1
+* IsMine hook to ensure modified clients don't spend namecoins by mistake as regular coins
  2
+* listtransactions decode
  3
+* name_update to a foreign address
  4
+* drop transactions that cannot be accepted because of a name conflict
  5
+* auto-send firstupdate after 6 blocks with persistent name/rand
  6
+* review threading
  7
+* DNS zone creator
  8
+* cross-mining
30  docs/vincent.gpg
... ...
@@ -0,0 +1,30 @@
  1
+-----BEGIN PGP PUBLIC KEY BLOCK-----
  2
+Version: GnuPG v1.4.10 (GNU/Linux)
  3
+
  4
+mQENBE2qMUsBCACtEgtFHji0PWq7hQCCmVSrfLdmKjiKQlIFdXmHIGWkC4DGmj13
  5
+m2zuwdLQO3Ph4Bs7vxymf55Cv/W6OCtxfgOV0oq//uLPjQmLK1l4EXm+6LSYbsUG
  6
+lzwrR9t9CfnKG7JHvj5mMlntHw4hPNKAAAginr4KqqluXr4bVPZKVB746Gpjafk3
  7
+aibqvqt+9uGnVsWJoKnQm2vbK0qnuhhEvVTyYOcy3+kxcfNJo29b7tyLCL4nxogf
  8
+NevzhBjUmd7Ur7EJW32xnKc9aIadyZTRqfM1mb709jLC8TljCP90N5l9q/UGZbIZ
  9
+avosR6sWuf398z1/AOGLopxvS/AnL92SVY4pABEBAAG0DlZpbmNlbnQgRHVyaGFt
  10
+iQE3BBMBCAAhBQJNqjFLAhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEJz+
  11
+siqjwOQO2tIH/1NlyQECefZr7U9SaI2MxjXBy9is7gM0rmiPsWH8SG/BG+A+D0W5
  12
+Z52miKDJn1kkoU0GQiGTrYIrQBu98heIKKQdftOrtU6f+wU7negLR9yaeoxGI1N7
  13
+eeKm9IGy1lnUAFby71A5O+sN+Q822D0tn+6MILkmX7U2pCROH7kXQjorrILXXL60
  14
+G0ITseUDbawfjyydBdZbJbvPaBH834FzoS5JfmNoEKKiQO9RQ3xoMcS0V1Mujl/X
  15
+EEQvPJUmPZxk3R0WDIIJJr1m2SeuFKEoRWzqUPGLoYK7REUswD+2E19X8eByKuHa
  16
+mJ5Q/C/orFRq4Zf5gEywScAva9TuyhFpe+q5AQ0ETaoxSwEIAKHx24c0WiU3N0s1
  17
+loZMkpcEpaWz4/0VML6s0Iw+tYnjJjjOMEzyovam73g/yyYuqmgvlyObrP6+kGx+
  18
+R/Gtbm7khaSpjvHYXlriSC4zT45N/Is4lQDwYd5BxeQR+k97SBSVsfU94n4sE3xo
  19
+lnfjroi8i4giockeNo1aYYmj5WSfoxAfF6R325SwUMiUjXVxaE/ZfsweOJc2FMlF
  20
+zIxiKvjkSYsFz1JfurY+0oVRImiS4LiGPiFVI5xd2I1IQu7T0GGsTnYi2hkaI23b
  21
+7id1jzUJWffCcsJH1NZwahsgzJurbO3ux/V8r7bbfkGGIYgAcJI3N5adk6G47vrp
  22
+xPKX/t8AEQEAAYkBHwQYAQgACQUCTaoxSwIbDAAKCRCc/rIqo8DkDnhQB/wL0Dz7
  23
+23UnXRG0V4lQCw17Svhgmuq1NkI3K5KUGq+KCABj2v+zF0svFWiiISbTt1gqCgcx
  24
+ARJrlFfnAXJteeNfPAoiKKouYTeHlHcwoBI1YaTW3CioNb2DpOSEXoS/Ks8W/hbW
  25
+rbTG+RuKvhnMVIeEu+CO/lC1wISVT8cGEc9P+XTYexMTVB2QiUoxaUjw0Wc/1wHn
  26
+AUzH8a1iNZUSgaCPljsI5HWyQEY+REw+rBdEoeJmKi7+N9FeqfVLt8mLThqoh3O7
  27
+3GI1J40k+e9MTQL5d+paPdB5+jbFLh6TU4Pgo0notrwvWUchkNxfvfjCurglj0Zj
  28
+zpci3ARTmPQeOTQt
  29
+=+Gix
  30
+-----END PGP PUBLIC KEY BLOCK-----
1,240  namecoin.cpp
... ...
@@ -0,0 +1,1240 @@
  1
+// Copyright (c) 2010-2011 Vincent Durham
  2
+// Distributed under the MIT/X11 software license, see the accompanying
  3
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
  4
+//
  5
+#include "headers.h"
  6
+
  7
+#include "namecoin.h"
  8
+
  9
+#include "json/json_spirit_reader_template.h"
  10
+#include "json/json_spirit_writer_template.h"
  11
+#include "json/json_spirit_utils.h"
  12
+
  13
+using namespace json_spirit;
  14
+
  15
+static const bool NAME_DEBUG = true;
  16
+typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
  17
+extern map<string, rpcfn_type> mapCallTable;
  18
+extern int64 AmountFromValue(const Value& value);
  19
+extern Object JSONRPCError(int code, const string& message);
  20
+template<typename T> void ConvertTo(Value& value);
  21
+
  22
+extern bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet);
  23
+
  24
+static const int NAMECOIN_TX_VERSION = 0x7100;
  25
+static const int64 MIN_AMOUNT = CENT;
  26
+static const int MAX_NAME_LENGTH = 255;
  27
+static const int MAX_VALUE_LENGTH = 1023;
  28
+static const int OP_NAME_INVALID = 0x00;
  29
+static const int OP_NAME_NEW = 0x01;
  30
+static const int OP_NAME_FIRSTUPDATE = 0x02;
  31
+static const int OP_NAME_UPDATE = 0x03;
  32
+static const int OP_NAME_NOP = 0x04;
  33
+static const int MIN_FIRSTUPDATE_DEPTH = 12;
  34
+static const int EXPIRATION_DEPTH = 12000;
  35
+
  36
+map<vector<unsigned char>, uint256> mapMyNames;
  37
+extern CCriticalSection cs_mapWallet;
  38
+
  39
+// forward decls
  40
+extern bool DecodeNameScript(const CScript& script, int& op, vector<vector<unsigned char> > &vvch);
  41
+extern bool DecodeNameScript(const CScript& script, int& op, vector<vector<unsigned char> > &vvch, CScript::const_iterator& pc);
  42
+extern int IndexOfNameOutput(CWalletTx& wtx);
  43
+extern bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet);
  44
+extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int nHashType);
  45
+extern bool GetValueOfNameTx(const CTransaction& tx, vector<unsigned char>& value);
  46
+
  47
+const int NAME_COIN_GENESIS_EXTRA = 521;
  48
+uint256 hashNameCoinGenesisBlock("000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770");
  49
+
  50
+class CNamecoinHooks : public CHooks
  51
+{
  52
+public:
  53
+    virtual bool IsStandard(const CScript& scriptPubKey);
  54
+    virtual void AddToWallet(CWalletTx& tx);
  55
+    virtual bool CheckTransaction(const CTransaction& tx);
  56
+    virtual bool ConnectInputs(CTxDB& txdb,
  57
+            const CTransaction& tx,
  58
+            vector<CTransaction>& vTxPrev,
  59
+            vector<CTxIndex>& vTxindex,
  60
+            CBlockIndex* pindexBlock,
  61
+            CDiskTxPos& txPos,
  62
+            bool fBlock,
  63
+            bool fMiner);
  64
+    virtual bool DisconnectInputs(CTxDB& txdb,
  65
+            const CTransaction& tx,
  66
+            CBlockIndex* pindexBlock);
  67
+    virtual bool ConnectBlock(CBlock& block, CTxDB& txdb, CBlockIndex* pindex);
  68
+    virtual bool DisconnectBlock(CBlock& block, CTxDB& txdb, CBlockIndex* pindex);
  69
+    virtual bool ExtractAddress(const CScript& script, string& address);
  70
+    virtual bool GenesisBlock(CBlock& block);
  71
+    virtual bool Lockin(int nHeight, uint256 hash);
  72
+    virtual int LockinHeight();
  73
+    virtual string IrcPrefix();
  74
+
  75
+    virtual void MessageStart(char* pchMessageStart)
  76
+    {
  77
+        // Make the message start different
  78
+        pchMessageStart[3] = 0xfe;
  79
+    }
  80
+};
  81
+
  82
+int64 getAmount(Value value)
  83
+{
  84
+    ConvertTo<double>(value);
  85
+    double dAmount = value.get_real();
  86
+    int64 nAmount = roundint64(dAmount * COIN);
  87
+    if (!MoneyRange(nAmount))
  88
+        throw JSONRPCError(-3, "Invalid amount");
  89
+    return nAmount;
  90
+}
  91
+
  92
+vector<unsigned char> vchFromValue(const Value& value) {
  93
+    string strName = value.get_str();
  94
+    unsigned char *strbeg = (unsigned char*)strName.c_str();
  95
+    return vector<unsigned char>(strbeg, strbeg + strName.size());
  96
+}
  97
+
  98
+vector<unsigned char> vchFromString(string str) {
  99
+    unsigned char *strbeg = (unsigned char*)str.c_str();
  100
+    return vector<unsigned char>(strbeg, strbeg + str.size());
  101
+}
  102
+
  103
+string stringFromVch(vector<unsigned char> vch) {
  104
+    string res;
  105
+    vector<unsigned char>::iterator vi = vch.begin();
  106
+    while (vi != vch.end()) {
  107
+        res += (char)(*vi);
  108
+        vi++;
  109
+    }
  110
+    return res;
  111
+}
  112
+
  113
+int64 GetNetworkFee(int nHeight)
  114
+{
  115
+  int64 nStart = 50 * COIN;
  116
+  if (fTestNet)
  117
+      nStart = 10 * CENT;
  118
+  int64 nRes = nStart >> (nHeight >> 13);
  119
+  nRes -= (nRes >> 14) * (nHeight % 8192);
  120
+  return nRes;
  121
+}
  122
+
  123
+int GetTxPosHeight(const CDiskTxPos& txPos)
  124
+{
  125
+    // Read block header
  126
+    CBlock block;
  127
+    if (!block.ReadFromDisk(txPos.nFile, txPos.nBlockPos, false))
  128
+        return 0;
  129
+    // Find the block in the index
  130
+    map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.GetHash());
  131
+    if (mi == mapBlockIndex.end())
  132
+        return 0;
  133
+    CBlockIndex* pindex = (*mi).second;
  134
+    if (!pindex || !pindex->IsInMainChain())
  135
+        return 0;
  136
+    return pindex->nHeight;
  137
+}
  138
+
  139
+
  140
+int GetNameHeight(CTxDB& txdb, vector<unsigned char> vchName) {
  141
+    CNameDB dbName("cr", txdb);
  142
+    vector<CDiskTxPos> vtxPos;
  143
+    if (dbName.ExistsName(vchName))
  144
+    {
  145
+        if (!dbName.ReadName(vchName, vtxPos))
  146
+            return error("GetNameHeight() : failed to read from name DB");
  147
+        if (vtxPos.empty())
  148
+            return -1;
  149
+        CDiskTxPos& txPos = vtxPos.back();
  150
+        return GetTxPosHeight(txPos);
  151
+    }
  152
+    return -1;
  153
+}
  154
+
  155
+CScript RemoveNameScriptPrefix(const CScript& scriptIn)
  156
+{
  157
+    int op;
  158
+    vector<vector<unsigned char> > vvch;
  159
+    CScript::const_iterator pc = scriptIn.begin();
  160
+
  161
+    if (!DecodeNameScript(scriptIn, op, vvch,  pc))
  162
+        throw runtime_error("RemoveNameScriptPrefix() : could not decode name script");
  163
+    return CScript(pc, scriptIn.end());
  164
+}
  165
+
  166
+bool SignNameSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL, CScript scriptPrereq=CScript())
  167
+{
  168
+    assert(nIn < txTo.vin.size());
  169
+    CTxIn& txin = txTo.vin[nIn];
  170
+    assert(txin.prevout.n < txFrom.vout.size());
  171
+    const CTxOut& txout = txFrom.vout[txin.prevout.n];
  172
+
  173
+    // Leave out the signature from the hash, since a signature can't sign itself.
  174
+    // The checksig op will also drop the signatures from its hash.
  175
+
  176
+    const CScript& scriptPubKey = RemoveNameScriptPrefix(txout.scriptPubKey);
  177
+    uint256 hash = SignatureHash(scriptPrereq + txout.scriptPubKey, txTo, nIn, nHashType);
  178
+
  179
+    if (!Solver(scriptPubKey, hash, nHashType, txin.scriptSig))
  180
+        return false;
  181
+
  182
+    txin.scriptSig = scriptPrereq + txin.scriptSig;
  183
+
  184
+    // Test solution
  185
+    if (scriptPrereq.empty())
  186
+        if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, 0))
  187
+            return false;
  188
+
  189
+    return true;
  190
+}
  191
+
  192
+
  193
+bool CreateTransactionWithInputTx(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxIn, int nTxOut, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
  194
+{
  195
+    int64 nValue = 0;
  196
+    foreach (const PAIRTYPE(CScript, int64)& s, vecSend)
  197
+    {
  198
+        if (nValue < 0)
  199
+            return false;
  200
+        nValue += s.second;
  201
+    }
  202
+    if (vecSend.empty() || nValue < 0)
  203
+        return false;
  204
+
  205
+    CRITICAL_BLOCK(cs_main)
  206
+    {
  207
+        // txdb must be opened before the mapWallet lock
  208
+        CTxDB txdb("r");
  209
+        CRITICAL_BLOCK(cs_mapWallet)
  210
+        {
  211
+            nFeeRet = nTransactionFee;
  212
+            loop
  213
+            {
  214
+                wtxNew.vin.clear();
  215
+                wtxNew.vout.clear();
  216
+                wtxNew.fFromMe = true;
  217
+
  218
+                int64 nTotalValue = nValue + nFeeRet;
  219
+                printf("total value = %d\n", nTotalValue);
  220
+                double dPriority = 0;
  221
+                // vouts to the payees
  222
+                foreach (const PAIRTYPE(CScript, int64)& s, vecSend)
  223
+                    wtxNew.vout.push_back(CTxOut(s.second, s.first));
  224
+
  225
+                int64 nWtxinCredit;
  226
+
  227
+                if (wtxIn.fSpent)
  228
+                {
  229
+                    // non-name outputs have been spent, only grab name output value
  230
+                    nWtxinCredit = wtxIn.vout[nTxOut].nValue;
  231
+                    printf("input credit / spent = %d\n", nWtxinCredit);
  232
+                }
  233
+                else
  234
+                {
  235
+                    // no part of wtxIn was spent, grab the entire coin
  236
+                    nWtxinCredit = wtxIn.GetCredit();
  237
+                    printf("input credit / non-spent = %d\n", nWtxinCredit);
  238
+                }
  239
+
  240
+                // Choose coins to use
  241
+                set<CWalletTx*> setCoins;
  242
+                if (!SelectCoins(nTotalValue - nWtxinCredit, setCoins))
  243
+                    return false;
  244
+                int64 nValueIn = 0;
  245
+
  246
+                vector<CWalletTx*> vecCoins(setCoins.begin(), setCoins.end());
  247
+
  248
+                foreach(CWalletTx* pcoin, vecCoins)
  249
+                {
  250
+                    // wtxIn non-name outputs might have been spent
  251
+                    int64 nCredit = pcoin->GetCredit();
  252
+                    nValueIn += nCredit;
  253
+                    dPriority += (double)nCredit * pcoin->GetDepthInMainChain();
  254
+                }
  255
+
  256
+                // Input tx always at first position
  257
+                vecCoins.insert(vecCoins.begin(), &wtxIn);
  258
+
  259
+                nValueIn += nWtxinCredit;
  260
+                dPriority += (double)nWtxinCredit * wtxIn.GetDepthInMainChain();
  261
+
  262
+                // Fill a vout back to self with any change
  263
+                int64 nChange = nValueIn - nTotalValue;
  264
+                printf("change = %d\n", nChange);
  265
+                if (nChange >= CENT)
  266
+                {
  267
+                    // Note: We use a new key here to keep it from being obvious which side is the change.
  268
+                    //  The drawback is that by not reusing a previous key, the change may be lost if a
  269
+                    //  backup is restored, if the backup doesn't have the new private key for the change.
  270
+                    //  If we reused the old key, it would be possible to add code to look for and
  271
+                    //  rediscover unknown transactions that were written with keys of ours to recover
  272
+                    //  post-backup change.
  273
+
  274
+                    // Reserve a new key pair from key pool
  275
+                    vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
  276
+                    assert(mapKeys.count(vchPubKey));
  277
+
  278
+                    // Fill a vout to ourself, using same address type as the payment
  279
+                    CScript scriptChange;
  280
+                    if (vecSend[0].first.GetBitcoinAddressHash160() != 0)
  281
+                        scriptChange.SetBitcoinAddress(vchPubKey);
  282
+                    else
  283
+                        scriptChange << vchPubKey << OP_CHECKSIG;
  284
+
  285
+                    // Insert change txn at random position:
  286
+                    vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
  287
+                    wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
  288
+                }
  289
+                else
  290
+                    reservekey.ReturnKey();
  291
+
  292
+                // Fill vin
  293
+                foreach(CWalletTx* pcoin, vecCoins)
  294
+                    for (int nOut = 0; nOut < pcoin->vout.size(); nOut++)
  295
+                    {
  296
+                        // three cases:
  297
+                        // * this is wtxIn name output, which can only be spent by this function - grab it
  298
+                        // * this is a wtxIn non-name output and the non-name part of the coin was already spent - skip
  299
+                        // * this is not wtxIn - we already checked it wasn't spent, grab it
  300
+                        if (pcoin == &wtxIn && nOut == nTxOut)
  301
+                        {
  302
+                            if (pcoin->vout[nOut].IsMine())
  303
+                                throw runtime_error("CreateTransactionWithInputTx() : wtxIn[nTxOut] already mine");
  304
+                            wtxNew.vin.push_back(CTxIn(pcoin->GetHash(), nOut));
  305
+                        }
  306
+                        else if (!pcoin->fSpent && pcoin->vout[nOut].IsMine())
  307
+                            wtxNew.vin.push_back(CTxIn(pcoin->GetHash(), nOut));
  308
+                    }
  309
+
  310
+                // Sign
  311
+                int nIn = 0;
  312
+                foreach(CWalletTx* pcoin, vecCoins)
  313
+                    for (int nOut = 0; nOut < pcoin->vout.size(); nOut++)
  314
+                    {
  315
+                        if (pcoin == &wtxIn && nOut == nTxOut)
  316
+                        {
  317
+                            if (!SignNameSignature(*pcoin, wtxNew, nIn++))
  318
+                                throw runtime_error("could not sign name coin output");
  319
+                        }
  320
+                        else if (!pcoin->fSpent && pcoin->vout[nOut].IsMine())
  321
+                            if (!SignSignature(*pcoin, wtxNew, nIn++))
  322
+                                return false;
  323
+                    }
  324
+
  325
+                // Limit size
  326
+                unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
  327
+                if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
  328
+                    return false;
  329
+                dPriority /= nBytes;
  330
+
  331
+                // Check that enough fee is included
  332
+                int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
  333
+                bool fAllowFree = CTransaction::AllowFree(dPriority);
  334
+                int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree);
  335
+                if (nFeeRet < max(nPayFee, nMinFee))
  336
+                {
  337
+                    nFeeRet = max(nPayFee, nMinFee);
  338
+                    continue;
  339
+                }
  340
+
  341
+                // Fill vtxPrev by copying from previous transactions vtxPrev
  342
+                wtxNew.AddSupportingTransactions(txdb);
  343
+                wtxNew.fTimeReceivedIsTxTime = true;
  344
+
  345
+                break;
  346
+            }
  347
+        }
  348
+    }
  349
+    return true;
  350
+}
  351
+
  352
+// nTxOut is the output from wtxIn that we should grab
  353
+string SendMoneyWithInputTx(CScript scriptPubKey, int64 nValue, int64 nNetFee, CWalletTx& wtxIn, CWalletTx& wtxNew, bool fAskFee)
  354
+{
  355
+    int nTxOut = IndexOfNameOutput(wtxIn);
  356
+    CRITICAL_BLOCK(cs_main)
  357
+    {
  358
+        CReserveKey reservekey;
  359
+        int64 nFeeRequired;
  360
+        vector< pair<CScript, int64> > vecSend;
  361
+        vecSend.push_back(make_pair(scriptPubKey, nValue));
  362
+
  363
+        if (nNetFee)
  364
+        {
  365
+            CScript scriptFee;
  366
+            scriptFee << OP_RETURN;
  367
+            vecSend.push_back(make_pair(scriptFee, nNetFee));
  368
+        }
  369
+
  370
+        if (!CreateTransactionWithInputTx(vecSend, wtxIn, nTxOut, wtxNew, reservekey, nFeeRequired))
  371
+        {
  372
+            string strError;
  373
+            if (nValue + nFeeRequired > GetBalance())
  374
+                strError = strprintf(_("Error: This is an oversized transaction that requires a transaction fee of %s  "), FormatMoney(nFeeRequired).c_str());
  375
+            else
  376
+                strError = _("Error: Transaction creation failed  ");
  377
+            printf("SendMoney() : %s", strError.c_str());
  378
+            return strError;
  379
+        }
  380
+
  381
+        if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
  382
+            return "ABORTED";
  383
+
  384
+        if (!CommitTransaction(wtxNew, reservekey))
  385
+            return _("Error: The transaction was rejected.  This might happen 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.");
  386
+    }
  387
+    MainFrameRepaint();
  388
+    return "";
  389
+}
  390
+
  391
+
  392
+bool GetValueOfTxPos(const CDiskTxPos& txPos, vector<unsigned char>& vchValue, int& nHeight)
  393
+{
  394
+    nHeight = GetTxPosHeight(txPos);
  395
+    CTransaction tx;
  396
+    if (!tx.ReadFromDisk(txPos))
  397
+        return error("GetValueOfTxPos() : could not read tx from disk");
  398
+    if (!GetValueOfNameTx(tx, vchValue))
  399
+        return error("GetValueOfTxPos() : could not decode value from tx");
  400
+}
  401
+
  402
+bool GetValueOfName(CNameDB& dbName, vector<unsigned char> vchName, vector<unsigned char>& vchValue, int& nHeight)
  403
+{
  404
+    vector<CDiskTxPos> vtxPos;
  405
+    if (!dbName.ReadName(vchName, vtxPos) || vtxPos.empty())
  406
+        return false;
  407
+    CDiskTxPos& txPos = vtxPos.back();
  408
+    return GetValueOfTxPos(txPos, vchValue, nHeight);
  409
+}
  410
+
  411
+Value name_list(const Array& params, bool fHelp)
  412
+{
  413
+    if (fHelp)
  414
+        throw runtime_error(
  415
+                "name_list [<name>]\n"
  416
+                "list my own names"
  417
+                );
  418
+
  419
+    map<vector<unsigned char>, uint256>::iterator mi;
  420
+    if (params.size() > 0)
  421
+    {
  422
+        vector<unsigned char> vchName = vchFromValue(params[0]);
  423
+        mi = mapMyNames.find(vchName);
  424
+    }
  425
+    else
  426
+    {
  427
+        mi = mapMyNames.begin();
  428
+    }
  429
+
  430
+    CNameDB dbName("cr");
  431
+    Array oRes;
  432
+
  433
+    while (mi != mapMyNames.end()) {
  434
+        Object oName;
  435
+        string name = stringFromVch((*mi).first);
  436
+        oName.push_back(Pair("name", name));
  437
+        vector<unsigned char> vchValue;
  438
+        int nHeight;
  439
+        if (GetValueOfName(dbName, (*mi).first, vchValue, nHeight))
  440
+        {
  441
+            string value = stringFromVch(vchValue);
  442
+            oName.push_back(Pair("value", value));
  443
+            oName.push_back(Pair("expires_in", nHeight + EXPIRATION_DEPTH - pindexBest->nHeight));
  444
+        }
  445
+        else
  446
+        {
  447
+            oName.push_back(Pair("expired", 1));
  448
+        }
  449
+        oRes.push_back(oName);
  450
+        mi++;
  451
+    }
  452
+
  453
+    if (NAME_DEBUG) {
  454
+        dbName.test();
  455
+    }
  456
+    return oRes;
  457
+}
  458
+
  459
+Value name_scan(const Array& params, bool fHelp)
  460
+{
  461
+    if (fHelp)
  462
+        throw runtime_error(
  463
+                "name_scan [<start-name>] [<max-returned>]\n"
  464
+                "scan all names, starting at start-name and returning a maximum number of entries (default 500)\n"
  465
+                );
  466
+
  467
+    vector<unsigned char> vchName;
  468
+    int nMax = 500;
  469
+    if (params.size() > 0)
  470
+    {
  471
+        vchName = vchFromValue(params[0]);
  472
+    }
  473
+
  474
+    if (params.size() > 1)
  475
+    {
  476
+        Value vMax = params[1];
  477
+        ConvertTo<double>(vMax);
  478
+        nMax = (int)vMax.get_real();
  479
+    }
  480
+
  481
+    CNameDB dbName("r");
  482
+    Array oRes;
  483
+
  484
+    vector<pair<vector<unsigned char>, CDiskTxPos> > nameScan;
  485
+    if (!dbName.ScanNames(vchName, nMax, nameScan))
  486
+        throw JSONRPCError(-4, "scan failed");
  487
+
  488
+    pair<vector<unsigned char>, CDiskTxPos> pairScan;
  489
+    foreach (pairScan, nameScan)
  490
+    {
  491
+        Object oName;
  492
+        string name = stringFromVch(pairScan.first);
  493
+        CDiskTxPos txPos = pairScan.second;
  494
+        oName.push_back(Pair("name", name));
  495
+        vector<unsigned char> vchValue;
  496
+        int nHeight;
  497
+        if (!txPos.IsNull() && GetValueOfTxPos(txPos, vchValue, nHeight))
  498
+        {
  499
+            string value = stringFromVch(vchValue);
  500
+            oName.push_back(Pair("value", value));
  501
+            oName.push_back(Pair("expires_in", nHeight + EXPIRATION_DEPTH - pindexBest->nHeight));
  502
+        }
  503
+        else
  504
+        {
  505
+            oName.push_back(Pair("expired", 1));
  506
+        }
  507
+        oRes.push_back(oName);
  508
+    }
  509
+
  510
+    if (NAME_DEBUG) {
  511
+        dbName.test();
  512
+    }
  513
+    return oRes;
  514
+}
  515
+
  516
+Value name_firstupdate(const Array& params, bool fHelp)
  517
+{
  518
+    if (fHelp)
  519
+        throw runtime_error(
  520
+                "name_firstupdate <name> <rand> [<tx>] <value> <network-fee-amount>\n"
  521
+                "Perform a first update after a name_new reservation.\n"
  522
+                "Note that the first update will go into a block 12 blocks after the name_new, at the soonest."
  523
+                );
  524
+    vector<unsigned char> vchName = vchFromValue(params[0]);
  525
+    vector<unsigned char> vchRand = ParseHex(params[1].get_str());
  526
+    vector<unsigned char> vchTx;
  527
+    vector<unsigned char> vchValue;
  528
+
  529
+    if (params.size() == 3)
  530
+    {
  531
+        vchValue = vchFromValue(params[2]);
  532
+    }
  533
+    else
  534
+    {
  535
+        vchValue = vchFromValue(params[3]);
  536
+    }
  537
+
  538
+
  539
+    CWalletTx wtx;
  540
+    wtx.nVersion = NAMECOIN_TX_VERSION;
  541
+    vector<unsigned char> strPubKey = GetKeyFromKeyPool();
  542
+    CScript scriptPubKeyOrig;
  543
+    scriptPubKeyOrig.SetBitcoinAddress(strPubKey);
  544
+    CScript scriptPubKey;
  545
+    scriptPubKey << OP_NAME_FIRSTUPDATE << vchName << vchRand << vchValue << OP_2DROP << OP_2DROP;
  546
+    scriptPubKey += scriptPubKeyOrig;
  547
+
  548
+    CRITICAL_BLOCK(cs_main)
  549
+    {
  550
+        // Make sure there is a previous NAME_NEW tx on this name
  551
+        // and that the random value matches
  552
+        uint256 wtxInHash;
  553
+        if (params.size() == 3)
  554
+        {
  555
+            if (!mapMyNames.count(vchName))
  556
+            {
  557
+                throw runtime_error("could not find a coin with this name");
  558
+            }
  559
+            wtxInHash = mapMyNames[vchName];
  560
+        }
  561
+        else
  562
+        {
  563
+            wtxInHash.SetHex(params[2].get_str());
  564
+        }
  565
+        CWalletTx& wtxIn = mapWallet[wtxInHash];
  566
+        vector<unsigned char> vchHash;
  567
+        bool found = false;
  568
+        foreach (CTxOut& out, wtxIn.vout)
  569
+        {
  570
+            vector<vector<unsigned char> > vvch;
  571
+            int op;
  572
+            if (DecodeNameScript(out.scriptPubKey, op, vvch)) {
  573
+                if (op != OP_NAME_NEW)
  574
+                    throw runtime_error("previous transaction wasn't a name_new");
  575
+                vchHash = vvch[0];
  576
+                found = true;
  577
+            }
  578
+        }
  579
+
  580
+        if (!found)
  581
+        {
  582
+            throw runtime_error("previous tx on this name is not a name tx");
  583
+        }
  584
+        vector<unsigned char> vchToHash(vchRand);
  585
+        vchToHash.insert(vchToHash.end(), vchName.begin(), vchName.end());
  586
+        uint160 hash =  Hash160(vchToHash);
  587
+        if (uint160(vchHash) != hash)
  588
+        {
  589
+            throw runtime_error("previous tx used a different random value");
  590
+        }
  591
+
  592
+        int64 nNetFee = GetNetworkFee(pindexBest->nHeight);
  593
+        // Round up to CENT
  594
+        nNetFee += CENT - 1;
  595
+        nNetFee = (nNetFee / CENT) * CENT;
  596
+        string strError = SendMoneyWithInputTx(scriptPubKey, MIN_AMOUNT, nNetFee, wtxIn, wtx, false);
  597
+        if (strError != "")
  598
+            throw JSONRPCError(-4, strError);
  599
+    }
  600
+    return wtx.GetHash().GetHex();
  601
+}
  602
+
  603
+Value name_update(const Array& params, bool fHelp)
  604
+{
  605
+    if (fHelp)
  606
+        throw runtime_error(
  607
+                "name_update <name> <value> <network-fee-amount>\n"
  608
+                );
  609
+
  610
+    vector<unsigned char> vchName = vchFromValue(params[0]);
  611
+    vector<unsigned char> vchValue = vchFromValue(params[1]);
  612
+
  613
+    CWalletTx wtx;
  614
+    wtx.nVersion = NAMECOIN_TX_VERSION;
  615
+    vector<unsigned char> strPubKey = GetKeyFromKeyPool();
  616
+    CScript scriptPubKeyOrig;
  617
+    scriptPubKeyOrig.SetBitcoinAddress(strPubKey);
  618
+    CScript scriptPubKey;
  619
+    scriptPubKey << OP_NAME_UPDATE << vchName << vchValue << OP_2DROP << OP_DROP;
  620
+    scriptPubKey += scriptPubKeyOrig;
  621
+
  622
+    CRITICAL_BLOCK(cs_main)
  623
+    {
  624
+        if (!mapMyNames.count(vchName))
  625
+        {
  626
+            throw runtime_error("could not find a coin with this name");
  627
+        }
  628
+        uint256 wtxInHash = mapMyNames[vchName];
  629
+        CWalletTx& wtxIn = mapWallet[wtxInHash];
  630
+        string strError = SendMoneyWithInputTx(scriptPubKey, MIN_AMOUNT, 0, wtxIn, wtx, false);
  631
+        if (strError != "")
  632
+            throw JSONRPCError(-4, strError);
  633
+    }
  634
+    return wtx.GetHash().GetHex();
  635
+}
  636
+
  637
+Value name_new(const Array& params, bool fHelp)
  638
+{
  639
+    if (fHelp)
  640
+        throw runtime_error(
  641
+                "name_new <name>\n"
  642
+                );
  643
+
  644
+    vector<unsigned char> vchName = vchFromValue(params[0]);
  645
+
  646
+    CWalletTx wtx;
  647
+    wtx.nVersion = NAMECOIN_TX_VERSION;
  648
+
  649
+    uint64 rand = GetRand((uint64)-1);
  650
+    vector<unsigned char> vchRand = CBigNum(rand).getvch();
  651
+    vector<unsigned char> vchToHash(vchRand);
  652
+    vchToHash.insert(vchToHash.end(), vchName.begin(), vchName.end());
  653
+    uint160 hash =  Hash160(vchToHash);
  654
+
  655
+    vector<unsigned char> strPubKey = GetKeyFromKeyPool();
  656
+    CScript scriptPubKeyOrig;
  657
+    scriptPubKeyOrig.SetBitcoinAddress(strPubKey);
  658
+    CScript scriptPubKey;
  659
+    scriptPubKey << OP_NAME_NEW << hash << OP_2DROP;
  660
+    scriptPubKey += scriptPubKeyOrig;
  661
+
  662
+    string strError = SendMoney(scriptPubKey, MIN_AMOUNT, wtx, false);
  663
+    if (strError != "")
  664
+        throw JSONRPCError(-4, strError);
  665
+    mapMyNames[vchName] = wtx.GetHash();
  666
+    vector<Value> res;
  667
+    res.push_back(wtx.GetHash().GetHex());
  668
+    res.push_back(HexStr(vchRand));
  669
+    return res;
  670
+}
  671
+
  672
+bool CNameDB::test()
  673
+{
  674
+    Dbc* pcursor = GetCursor();
  675
+    if (!pcursor)
  676
+        return false;
  677
+
  678
+    loop
  679
+    {
  680
+        // Read next record
  681
+        CDataStream ssKey;
  682
+        CDataStream ssValue;
  683
+        int ret = ReadAtCursor(pcursor, ssKey, ssValue);
  684
+        if (ret == DB_NOTFOUND)
  685
+            break;
  686
+        else if (ret != 0)
  687
+            return false;
  688
+
  689
+        // Unserialize
  690
+        string strType;
  691
+        ssKey >> strType;
  692
+        if (strType == "namei")
  693
+        {
  694
+            vector<unsigned char> vchName;
  695
+            ssKey >> vchName;
  696
+            string strName = stringFromVch(vchName);
  697
+            vector<CDiskTxPos> vtxPos;
  698
+            ssValue >> vtxPos;
  699
+            if (NAME_DEBUG)
  700
+              printf("NAME %s : ", strName.c_str());
  701
+            foreach(CDiskTxPos& txPos, vtxPos) {
  702
+                txPos.print();
  703
+                if (NAME_DEBUG)
  704
+                  printf(" @ %d, ", GetTxPosHeight(txPos));
  705
+            }
  706
+            if (NAME_DEBUG)
  707
+              printf("\n");
  708
+        }
  709
+    }
  710
+    pcursor->close();
  711
+}
  712
+
  713
+bool CNameDB::ScanNames(
  714
+        const vector<unsigned char>& vchName,
  715
+        int nMax,
  716
+        vector<pair<vector<unsigned char>, CDiskTxPos> >& nameScan)
  717
+{
  718
+    Dbc* pcursor = GetCursor();
  719
+    if (!pcursor)
  720
+        return false;
  721
+
  722
+    unsigned int fFlags = DB_SET_RANGE;
  723
+    loop
  724
+    {
  725
+        // Read next record
  726
+        CDataStream ssKey;
  727
+        if (fFlags == DB_SET_RANGE)
  728
+            ssKey << make_pair(string("namei"), vchName);
  729
+        CDataStream ssValue;
  730
+        int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
  731
+        fFlags = DB_NEXT;
  732
+        if (ret == DB_NOTFOUND)
  733
+            break;
  734
+        else if (ret != 0)
  735
+            return false;
  736
+
  737
+        // Unserialize
  738
+        string strType;
  739
+        ssKey >> strType;
  740
+        if (strType == "namei")
  741
+        {
  742
+            vector<unsigned char> vchName;
  743
+            ssKey >> vchName;
  744
+            string strName = stringFromVch(vchName);
  745
+            vector<CDiskTxPos> vtxPos;
  746
+            ssValue >> vtxPos;
  747
+            CDiskTxPos txPos;
  748
+            if (!vtxPos.empty())
  749
+            {
  750
+                txPos = vtxPos.back();
  751
+            }
  752
+            nameScan.push_back(make_pair(vchName, txPos));
  753
+        }
  754
+
  755
+        if (nameScan.size() >= nMax)
  756
+            break;
  757
+    }
  758
+    pcursor->close();
  759
+    return true;
  760
+}
  761
+
  762
+CHooks* InitHook()
  763
+{
  764
+    mapCallTable.insert(make_pair("name_new", &name_new));
  765
+    mapCallTable.insert(make_pair("name_update", &name_update));
  766
+    mapCallTable.insert(make_pair("name_firstupdate", &name_firstupdate));
  767
+    mapCallTable.insert(make_pair("name_list", &name_list));
  768
+    mapCallTable.insert(make_pair("name_scan", &name_scan));
  769
+    hashGenesisBlock = hashNameCoinGenesisBlock;
  770
+    printf("Setup namecoin genesis block %s\n", hashGenesisBlock.GetHex().c_str());
  771
+    return new CNamecoinHooks();
  772
+}
  773
+
  774
+bool CNamecoinHooks::IsStandard(const CScript& scriptPubKey)
  775
+{
  776
+    return true;
  777
+}
  778
+
  779
+bool DecodeNameScript(const CScript& script, int& op, vector<vector<unsigned char> > &vvch)
  780
+{
  781
+    CScript::const_iterator pc = script.begin();
  782
+    return DecodeNameScript(script, op, vvch, pc);
  783
+}
  784
+
  785
+bool DecodeNameScript(const CScript& script, int& op, vector<vector<unsigned char> > &vvch, CScript::const_iterator& pc)
  786
+{
  787
+    opcodetype opcode;
  788
+    if (!script.GetOp(pc, opcode))
  789
+        return false;
  790
+    if (opcode < OP_1 || opcode > OP_16)
  791
+        return false;
  792
+
  793
+    op = opcode - OP_1 + 1;
  794
+
  795
+    for (;;) {
  796
+        vector<unsigned char> vch;
  797
+        if (!script.GetOp(pc, opcode, vch))
  798
+            return false;
  799
+        if (opcode == OP_DROP || opcode == OP_2DROP || opcode == OP_NOP)
  800
+            break;
  801
+        if (!(opcode >= 0 && opcode <= OP_PUSHDATA4))
  802
+            return false;
  803
+        vvch.push_back(vch);
  804
+    }
  805
+
  806
+    // move the pc to after any DROP or NOP
  807
+    while (opcode == OP_DROP || opcode == OP_2DROP || opcode == OP_NOP)
  808
+    {
  809
+        if (!script.GetOp(pc, opcode))
  810
+            break;
  811
+    }
  812
+
  813
+    pc--;
  814
+
  815
+    if ((op == OP_NAME_NEW && vvch.size() == 1) ||
  816
+            (op == OP_NAME_FIRSTUPDATE && vvch.size() == 3) ||
  817
+            (op == OP_NAME_UPDATE && vvch.size() == 2))
  818
+        return true;
  819
+    return error("invalid number of arguments for name op");
  820
+}
  821
+
  822
+bool DecodeNameTx(const CTransaction& tx, int& op, int& nOut, vector<vector<unsigned char> >& vvch)
  823
+{
  824
+    bool found = false;
  825
+
  826
+    for (int i = 0 ; i < tx.vout.size() ; i++)
  827
+    {
  828
+        const CTxOut& out = tx.vout[i];
  829
+        if (DecodeNameScript(out.scriptPubKey, op, vvch))
  830
+        {
  831
+            // If more than one name op, fail
  832
+            if (found)
  833
+                return false;
  834
+            nOut = i;
  835
+            found = true;
  836
+        }
  837
+    }
  838
+
  839
+    return found;
  840
+}
  841
+
  842
+int64 GetNameNetFee(const CTransaction& tx)
  843
+{
  844
+    int64 nFee = 0;
  845
+
  846
+    for (int i = 0 ; i < tx.vout.size() ; i++)
  847
+    {
  848
+        const CTxOut& out = tx.vout[i];
  849
+        if (out.scriptPubKey.size() == 1 && out.scriptPubKey[0] == OP_RETURN)
  850
+        {
  851
+            nFee += out.nValue;
  852
+        }
  853
+    }
  854
+
  855
+    return nFee;
  856
+}
  857
+
  858
+bool GetValueOfNameTx(const CTransaction& tx, vector<unsigned char>& value)
  859
+{
  860
+    vector<vector<unsigned char> > vvch;
  861
+
  862
+    int op;
  863
+    int nOut;
  864
+
  865
+    if (!DecodeNameTx(tx, op, nOut, vvch))
  866
+        return false;
  867
+
  868
+    switch (op)
  869
+    {
  870
+        case OP_NAME_NEW:
  871
+            return false;
  872
+        case OP_NAME_FIRSTUPDATE:
  873
+            value = vvch[2];
  874
+            return true;
  875
+        case OP_NAME_UPDATE:
  876
+            value = vvch[1];
  877
+            return true;
  878
+        default:
  879
+            return false;
  880
+    }
  881
+}
  882
+
  883
+int IndexOfNameOutput(CWalletTx& wtx)
  884
+{
  885
+    vector<vector<unsigned char> > vvch;
  886
+
  887
+    int op;
  888
+    int nOut;
  889
+
  890
+    bool good = DecodeNameTx(wtx, op, nOut, vvch);
  891
+
  892
+    if (!good)
  893
+        throw runtime_error("IndexOfNameOutput() : name output not found");
  894
+    return nOut;
  895
+}
  896
+
  897
+void CNamecoinHooks::AddToWallet(CWalletTx& wtx)
  898
+{
  899
+    if (wtx.nVersion != NAMECOIN_TX_VERSION)
  900
+        return;
  901
+
  902
+    if (wtx.vout.size() < 1)
  903
+    {
  904
+        error("AddToWalletHook() : no output in name tx %s", wtx.ToString().c_str());
  905
+        return;
  906
+    }
  907
+
  908
+    vector<vector<unsigned char> > vvch;
  909
+
  910
+    int op;
  911
+    int nOut;
  912
+
  913
+    bool good = DecodeNameTx(wtx, op, nOut, vvch);
  914
+
  915
+    if (!good)
  916
+    {
  917
+        error("AddToWalletHook() : no output out script in name tx %s", wtx.ToString().c_str());
  918
+        return;
  919
+    }
  920
+
  921
+    CRITICAL_BLOCK(cs_mapWallet)
  922
+    {
  923
+        if (!wtx.fSpent && op != OP_NAME_NEW)
  924
+            mapMyNames[vvch[0]] = wtx.GetHash();
  925
+    }
  926
+}
  927
+
  928
+int CheckTransactionAtRelativeDepth(CBlockIndex* pindexBlock, CTxIndex& txindex, int maxDepth)
  929
+{
  930
+    for (CBlockIndex* pindex = pindexBlock; pindex && pindexBlock->nHeight - pindex->nHeight < maxDepth; pindex = pindex->pprev)
  931
+        if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
  932
+            return pindexBlock->nHeight - pindex->nHeight;
  933
+    return -1;
  934
+}
  935
+
  936
+bool CNamecoinHooks::ConnectInputs(CTxDB& txdb,
  937
+        const CTransaction& tx,
  938
+        vector<CTransaction>& vTxPrev,
  939
+        vector<CTxIndex>& vTxindex,
  940
+        CBlockIndex* pindexBlock,
  941
+        CDiskTxPos& txPos,
  942
+        bool fBlock,
  943
+        bool fMiner)
  944
+{
  945
+    bool nInput;
  946
+    bool found = false;
  947
+
  948
+    int prevOp;
  949
+    vector<vector<unsigned char> > vvchPrevArgs;
  950
+
  951
+    for (int i = 0 ; i < tx.vin.size() ; i++) {
  952
+        CTxOut& out = vTxPrev[i].vout[tx.vin[i].prevout.n];
  953
+        if (DecodeNameScript(out.scriptPubKey, prevOp, vvchPrevArgs))
  954
+        {
  955
+            if (found)
  956
+                return error("ConnectInputHook() : multiple previous name transactions");
  957
+            found = true;
  958
+            nInput = i;
  959
+        }
  960
+    }
  961
+
  962
+    if (tx.nVersion != NAMECOIN_TX_VERSION)
  963
+    {
  964
+        // Make sure name-op outputs are not spent by a regular transaction, or the name
  965
+        // would be lost
  966
+        if (found)
  967
+            return error("ConnectInputHook() : a non-namecoin transaction with a namecoin input");
  968
+        return true;
  969
+    }
  970
+
  971
+    vector<vector<unsigned char> > vvchArgs;
  972
+    int op;
  973
+    int nOut;
  974
+
  975
+    bool good = DecodeNameTx(tx, op, nOut, vvchArgs);
  976
+    if (!good)
  977
+        return error("ConnectInputsHook() : could not decode a namecoin tx");
  978
+
  979
+    int nPrevHeight;
  980
+    int nDepth;
  981
+    int64 nNetFee;
  982
+
  983
+    switch (op)
  984
+    {
  985
+        case OP_NAME_NEW:
  986
+            if (found)
  987
+                return error("name_new tx pointing to previous namecoin tx");
  988
+            break;
  989
+        case OP_NAME_FIRSTUPDATE:
  990
+            nNetFee = GetNameNetFee(tx);
  991
+            if (nNetFee < GetNetworkFee(pindexBlock->nHeight))
  992
+                return error("got tx %s with fee too low %d", tx.GetHash().GetHex().c_str(), nNetFee);
  993
+            if (!found || prevOp != OP_NAME_NEW)
  994
+                return error("name_firstupdate tx without previous name_new tx");
  995
+            nPrevHeight = GetNameHeight(txdb, vvchArgs[0]);
  996
+            if (nPrevHeight >= 0 && pindexBlock->nHeight - nPrevHeight < EXPIRATION_DEPTH)
  997
+                return error("name_firstupdate on an unexpired name");
  998
+            nDepth = CheckTransactionAtRelativeDepth(pindexBlock, vTxindex[nInput], MIN_FIRSTUPDATE_DEPTH);
  999
+            // Do not accept if in chain and not mature
  1000
+            if ((fBlock || fMiner) && nDepth >= 0 && nDepth < MIN_FIRSTUPDATE_DEPTH)
  1001
+                return false;
  1002
+
  1003
+            // Do not mine if previous name_new is not visible.  This is if
  1004
+            // name_new expired or not yet in a block
  1005
+            if (fMiner)
  1006
+            {
  1007
+                // TODO CPU intensive
  1008
+                nDepth = CheckTransactionAtRelativeDepth(pindexBlock, vTxindex[nInput], EXPIRATION_DEPTH);
  1009
+                if (nDepth == -1)
  1010
+                    return error("name_firstupdate cannot be mined if name_new is not already in chain and unexpired");