Skip to content
This repository

JSON-RPC method: prioritisetransaction <txid> <priority delta> #1583

Open
wants to merge 1 commit into from

9 participants

Luke-Jr Jeff Garzik Gregory Maxwell BitcoinPullTester Pieter Wuille Peter Todd Gavin Andresen P. Kaufmann Wladimir J. van der Laan
Luke-Jr

Accepts the transaction into mined blocks at a higher (or lower) priority

Jeff Garzik
Collaborator

Code seems ACK-worthy.

Use cases?

Luke-Jr

Various people (@gmaxwell and @gavinandresen included) expressed interest in this - one example was to allow captcha-solving as an alternative to fees.

src/main.h
... ...
@@ -396,6 +399,9 @@ class CTransaction
396 399
     mutable int nDoS;
397 400
     bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
398 401
 
  402
+    double dPriorityDelta;
  403
+
1
P. Kaufmann
Diapolo added a note July 11, 2012

Have 2 empty lines a special meaning in the code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/main.h
... ...
@@ -540,6 +547,9 @@ class CTransaction
540 547
 
541 548
     int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, enum GetMinFee_mode mode=GMF_BLOCK) const
542 549
     {
  550
+        if (dPriorityDelta > 0)
4
Gavin Andresen Owner

What's the logic here? Why would setting a >0 delta automatically imply a minimum fee of zero?

Luke-Jr
luke-jr added a note July 12, 2012

It seems to me, that if someone wants to improve the priority of a transaction, they do actually want to mine that transaction. What's the point of setting a priority of a transaction that you're not going to mine regardless?

Gavin Andresen Owner

The point is "increase priority" and "requires no fee" should, in my opinion, be independent notions. Somebody might want to bump up the priority of transactions from the Bitcoin Faucet a little because they like the idea of giving newbies a good bitcoin experience, but don't want to crowd out other high-priority/low-fee transactions.

Luke-Jr
luke-jr added a note July 13, 2012

I can take this out if you want me to, but I don't see the point. A priority bump of just 1 has no practical effect on the overall priority comparison, but could be used to whitelist against the fee requirements, and the priority is entirely ignored if a transaction doesn't meet the fee requirements, so it makes no sense to increase the priority while not overriding the fee requirements, IMO.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/main.h
... ...
@@ -92,6 +92,9 @@
92 92
 bool SendMessages(CNode* pto, bool fSendTrickle);
93 93
 bool LoadExternalBlockFile(FILE* fileIn);
94 94
 void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
  95
+bool PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta);
  96
+bool PrioritiseTransaction(const uint256 hash, double dPriorityDelta);
  97
+bool PrioritiseTransaction(const std::string strHash, double dPriorityDelta);
1
Gavin Andresen Owner

Three versions of this is excessive. Less code, please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Gregory Maxwell
Collaborator

Re: Ignoring minfee: This call is by txid. If you don't like the fee, don't call it on the transaction. Ignoring minfee is the right thing to do here.

Though this should also have a fee delta, because we now prioritize above minfee txn by fee per KB. If someone is paying you behind the scenes to mine a transaction you should be able to add the amount you're being paid (or whatever) to the fee used in that calculation. e.g. prioritizetransaction .

Luke-Jr

Updated with suggestions. Also, is it intentional that GetMinFee with GMF_BLOCK is never used anymore?

Luke-Jr luke-jr referenced this pull request August 13, 2012
Closed

next 2012-08-13 #1671

BitcoinPullTester

Automatic sanity-testing: PASSED, see http://jenkins.bluematt.me/pull-tester/2c63ef9156288b3cc72668fdb6ce44ec3a440076 for binaries and test log.

Pieter Wuille
Collaborator
sipa commented August 13, 2012

@luke-jr Which commit removed the call to GetMinFee with GMF_BLOCK?

src/main.cpp
... ...
@@ -3349,6 +3349,23 @@ class COrphan
3349 3349
 };
3350 3350
 
3351 3351
 
  3352
+bool PrioritiseTransaction(const uint256 hash, const string strHash, double dPriorityDelta, int64 nFeeDelta)
  3353
+{
  3354
+    if (!mempool.mapTx.count(hash))
  3355
+    {
  3356
+        printf("PrioritiseTransaction: cannot find %s\n", strHash.c_str());
  3357
+        return false;
  3358
+    }
  3359
+
  3360
+    CTransaction &txn = mempool.mapTx[hash];
2
Pieter Wuille Collaborator
sipa added a note August 13, 2012

This needs a LOCK on mempool.cs, imho. Even if it's somehow already safe because of the lock on cs_main, I'd prefer having it there, for when RPC locks get pushed down.

Luke-Jr
luke-jr added a note August 13, 2012

Fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Gregory Maxwell
Collaborator

Needs a rebase

Luke-Jr

rebased

src/main.h
... ...
@@ -477,6 +479,10 @@ class CTransaction
477 479
     std::vector<CTxOut> vout;
478 480
     unsigned int nLockTime;
479 481
 
  482
+    double dPriorityDelta;
  483
+    int64 nFeeDelta;
2
Gavin Andresen Owner

Adding 16 bytes to every in-memory transaction to support a feature that will not be used by 99.9% of users seems like the wrong thing to do.

How about instead keeping a map<transaction_id, pair<priorityDelta,feeDelta> > in the memory pool class, and have prioritisetransaction add to that map?

Finally: need to check to see if the free transaction rate limiter code needs to take this into account (I assume you should be able to prioritisetransaction and then if you receive the transaction over the network it should sail through the limiter and make it into the memory pool -- or is it assumed that the transaction will get into the memory pool some other way, like a sendrawtransaction call?).

Luke-Jr
luke-jr added a note February 13, 2013

With the deltas stored on CTransaction, applying them to not-received ones was impractical. Obviously using a map as you suggest solves this problem too - will do that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Luke-Jr

Ok, finally redid this using a map.

@gavinandresen , look good?

Jeff Garzik
Collaborator
jgarzik commented May 30, 2013

No objection... though I still prioritize with the 'z' :) Who the heck uses an 's'? :)

src/main.cpp
... ...
@@ -574,6 +574,16 @@ bool CTransaction::CheckTransaction(CValidationState &state) const
574 574
 int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree,
575 575
                               enum GetMinFee_mode mode) const
576 576
 {
  577
+    {
  578
+        LOCK(mempool.cs);
  579
+        uint256 hash = GetHash();
  580
+        double dPriorityDelta = 0;
  581
+        int64 nFeeDelta = 0;
  582
+        mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
1
Wladimir J. van der Laan Owner
laanwj added a note May 30, 2013

I don't like all these side-effects in a const getter function

Edit: hmm, never mind, ApplyDeltas does not actually change anything in the mempool object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Luke-Jr

It occurs to me that the map should be cleaned at some point. Any opinions on when to remove a txid from it?

Gregory Maxwell
Collaborator

Check it when removing transactions from the mempool?

Luke-Jr

Probably don't want to lose priority adjustments if your block gets knocked off the main chain...

Peter Todd

@luke-jr Set a expiry height after they get knocked off the main chain and remove them from the map after n blocks? If n=100 is reached we have bigger problems...

Gavin Andresen

Rebase needed.

Luke-Jr

Rebased. For purging from the map.. how about when we see a block confirm a transaction using it as an input?

Luke-Jr

Rebased and added mapDeltas pruning when transactions are removed from the memory pool (ie, included in a block).

Luke-Jr JSON-RPC method: prioritisetransaction <txid> <priority delta> <prior…
…ity tx fee>

Accepts the transaction into mined blocks at a higher (or lower) priority
4427dc5
BitcoinPullTester

Automatic sanity-testing: PASSED, see http://jenkins.bluematt.me/pull-tester/4427dc5e6a6fd0f7349e6ea3e0d6a084491cf265 for binaries and test log.
This test script verifies pulls every time they are updated. It, however, dies sometimes and fails to test properly. If you are waiting on a test, please check timestamps to verify that the test.log is moving at http://jenkins.bluematt.me/pull-tester/current/
Contact BlueMatt on freenode if something looks broken.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

Feb 21, 2014
Luke-Jr JSON-RPC method: prioritisetransaction <txid> <priority delta> <prior…
…ity tx fee>

Accepts the transaction into mined blocks at a higher (or lower) priority
4427dc5
This page is out of date. Refresh to see the latest.
11  src/main.cpp
@@ -695,6 +695,16 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
695 695
 
696 696
 int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree, enum GetMinFee_mode mode)
697 697
 {
  698
+    {
  699
+        LOCK(mempool.cs);
  700
+        uint256 hash = tx.GetHash();
  701
+        double dPriorityDelta = 0;
  702
+        int64_t nFeeDelta = 0;
  703
+        mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
  704
+        if (dPriorityDelta > 0 || nFeeDelta > 0)
  705
+            return 0;
  706
+    }
  707
+
698 708
     // Base fee is either nMinTxFee or nMinRelayTxFee
699 709
     int64_t nBaseFee = (mode == GMF_RELAY) ? tx.nMinRelayTxFee : tx.nMinTxFee;
700 710
 
@@ -1911,6 +1921,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
1911 1921
     BOOST_FOREACH(const CTransaction &tx, block.vtx) {
1912 1922
         mempool.remove(tx);
1913 1923
         mempool.removeConflicts(tx);
  1924
+        mempool.ClearPrioritisation(tx.GetHash());
1914 1925
     }
1915 1926
     mempool.check(pcoinsTip);
1916 1927
     // Update chainActive & related variables.
43  src/miner.cpp
@@ -3,6 +3,8 @@
3 3
 // Distributed under the MIT/X11 software license, see the accompanying
4 4
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 5
 
  6
+#include <inttypes.h>
  7
+
6 8
 #include "miner.h"
7 9
 
8 10
 #include "core.h"
@@ -77,6 +79,35 @@ class COrphan
77 79
 };
78 80
 
79 81
 
  82
+void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, double dPriorityDelta, int64_t nFeeDelta)
  83
+{
  84
+    {
  85
+        LOCK(cs);
  86
+        std::pair<double, int64_t> &deltas = mapDeltas[hash];
  87
+        deltas.first += dPriorityDelta;
  88
+        deltas.second += nFeeDelta;
  89
+    }
  90
+    printf("PrioritiseTransaction: %s priority += %f, fee += %"PRId64"\n", strHash.c_str(), dPriorityDelta, nFeeDelta);
  91
+}
  92
+
  93
+void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, int64_t &nFeeDelta)
  94
+{
  95
+    LOCK(cs);
  96
+    std::map<uint256, std::pair<double, int64_t> >::iterator pos = mapDeltas.find(hash);
  97
+    if (pos == mapDeltas.end())
  98
+        return;
  99
+    const std::pair<double, int64_t> &deltas = pos->second;
  100
+    dPriorityDelta += deltas.first;
  101
+    nFeeDelta += deltas.second;
  102
+}
  103
+
  104
+void CTxMemPool::ClearPrioritisation(const uint256 hash)
  105
+{
  106
+    LOCK(cs);
  107
+    mapDeltas.erase(hash);
  108
+}
  109
+
  110
+
80 111
 uint64_t nLastBlockTx = 0;
81 112
 uint64_t nLastBlockSize = 0;
82 113
 
@@ -210,6 +241,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
210 241
             unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
211 242
             dPriority = tx.ComputePriority(dPriority, nTxSize);
212 243
 
  244
+            uint256 hash = tx.GetHash();
  245
+            mempool.ApplyDeltas(hash, dPriority, nTotalIn);
  246
+
213 247
             // This is a more accurate fee-per-kilobyte than is used by the client code, because the
214 248
             // client code rounds up the size to the nearest 1K. That's good, because it gives an
215 249
             // incentive to create smaller transactions.
@@ -254,10 +288,14 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
254 288
                 continue;
255 289
 
256 290
             // Skip free transactions if we're past the minimum block size:
257  
-            if (fSortedByFee && (dFeePerKb < CTransaction::nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
  291
+            uint256 hash = tx.GetHash();
  292
+            double dPriorityDelta = 0;
  293
+            int64_t nFeeDelta = 0;
  294
+            mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
  295
+            if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (dFeePerKb < CTransaction::nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
258 296
                 continue;
259 297
 
260  
-            // Prioritize by fee once past the priority size or we run out of high-priority
  298
+            // Prioritise by fee once past the priority size or we run out of high-priority
261 299
             // transactions:
262 300
             if (!fSortedByFee &&
263 301
                 ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority)))
@@ -281,7 +319,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
281 319
                 continue;
282 320
 
283 321
             CTxUndo txundo;
284  
-            uint256 hash = tx.GetHash();
285 322
             UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1, hash);
286 323
 
287 324
             // Added
2  src/rpcclient.cpp
@@ -150,6 +150,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
150 150
     if (strMethod == "listtransactions"       && n > 2) ConvertTo<boost::int64_t>(params[2]);
151 151
     if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
152 152
     if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
  153
+    if (strMethod == "prioritisetransaction"  && n > 1) ConvertTo<double>(params[1]);
  154
+    if (strMethod == "prioritisetransaction"  && n > 2) ConvertTo<boost::int64_t>(params[2]);
153 155
     if (strMethod == "getblocktemplate"       && n > 0) ConvertTo<Object>(params[0]);
154 156
     if (strMethod == "listsinceblock"         && n > 1) ConvertTo<boost::int64_t>(params[1]);
155 157
     if (strMethod == "sendmany"               && n > 1) ConvertTo<Object>(params[1]);
15  src/rpcmining.cpp
@@ -273,6 +273,21 @@ Value getmininginfo(const Array& params, bool fHelp)
273 273
 }
274 274
 
275 275
 
  276
+
  277
+Value prioritisetransaction(const Array& params, bool fHelp)
  278
+{
  279
+    if (fHelp || params.size() != 3)
  280
+        throw runtime_error(
  281
+            "prioritisetransaction <txid> <priority delta> <fee delta>\n"
  282
+            "Accepts the transaction into mined blocks at a higher (or lower) priority");
  283
+
  284
+    uint256 hash;
  285
+    hash.SetHex(params[0].get_str());
  286
+    mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), params[2].get_int64());
  287
+    return true;
  288
+}
  289
+
  290
+
276 291
 #ifdef ENABLE_WALLET
277 292
 Value getwork(const Array& params, bool fHelp)
278 293
 {
1  src/rpcserver.cpp
@@ -251,6 +251,7 @@ static const CRPCCommand vRPCCommands[] =
251 251
     /* Mining */
252 252
     { "getnetworkhashps",       &getnetworkhashps,       true,      false,      false },
253 253
     { "getmininginfo",          &getmininginfo,          true,      false,      false },
  254
+    { "prioritisetransaction",  &prioritisetransaction,  true,      false,      false },
254 255
     { "getblocktemplate",       &getblocktemplate,       true,      false,      false },
255 256
     { "submitblock",            &submitblock,            false,     false,      false },
256 257
     { "validateaddress",        &validateaddress,        true,      false,      false },
1  src/rpcserver.h
@@ -126,6 +126,7 @@ extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHe
126 126
 extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp);
127 127
 extern json_spirit::Value gethashespersec(const json_spirit::Array& params, bool fHelp);
128 128
 extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp);
  129
+extern json_spirit::Value prioritisetransaction(const json_spirit::Array& params, bool fHelp);
129 130
 extern json_spirit::Value getwork(const json_spirit::Array& params, bool fHelp);
130 131
 extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp);
131 132
 extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp);
6  src/txmempool.h
@@ -59,6 +59,7 @@ class CTxMemPool
59 59
     mutable CCriticalSection cs;
60 60
     std::map<uint256, CTxMemPoolEntry> mapTx;
61 61
     std::map<COutPoint, CInPoint> mapNextTx;
  62
+    std::map<uint256, std::pair<double, int64_t> > mapDeltas;
62 63
 
63 64
     CTxMemPool();
64 65
 
@@ -80,6 +81,11 @@ class CTxMemPool
80 81
     unsigned int GetTransactionsUpdated() const;
81 82
     void AddTransactionsUpdated(unsigned int n);
82 83
 
  84
+    /** Affect CreateNewBlock prioritisation of transactions */
  85
+    void PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, int64_t nFeeDelta);
  86
+    void ApplyDeltas(const uint256 hash, double &dPriorityDelta, int64_t &nFeeDelta);
  87
+    void ClearPrioritisation(const uint256 hash);
  88
+
83 89
     unsigned long size()
84 90
     {
85 91
         LOCK(cs);
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.