Skip to content

Commit

Permalink
getnewblockhex: add ability to pass over transactions based on mempoo…
Browse files Browse the repository at this point in the history
…l age
  • Loading branch information
instagibbs committed Apr 25, 2018
1 parent f87a264 commit ed121e8
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 10 deletions.
20 changes: 20 additions & 0 deletions qa/rpc-tests/mempool_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,25 @@ def chain_transaction(self, node, parent_txid, vout, value, fee, num_outputs):
return (txid, send_value)

def run_test(self):

# Create transaction with 3-second block delay, should fail to enter the template
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
block = self.nodes[0].getnewblockhex(required_age=3)
self.nodes[0].submitblock(block)
assert(txid in self.nodes[0].getrawmempool())
time.sleep(3)
block = self.nodes[0].getnewblockhex(required_age=3)
self.nodes[0].submitblock(block)
assert(txid not in self.nodes[0].getrawmempool())
# Once more with no delay (default is 0, just testing default arg)
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
block = self.nodes[0].getnewblockhex(required_age=0)
self.nodes[0].submitblock(block)
assert(txid not in self.nodes[0].getrawmempool())
assert_raises_message(JSONRPCException, "required_wait must be non-negative.", self.nodes[0].getnewblockhex, -1)

print("Rest of entire test is disabled due to fee outputs etc")

return #TODO
''' Mine some blocks and have them mature. '''
self.nodes[0].generate(101)
Expand Down Expand Up @@ -252,5 +271,6 @@ def run_test(self):
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
sync_blocks(self.nodes)


if __name__ == '__main__':
MempoolPackagesTest().main()
14 changes: 9 additions & 5 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ void BlockAssembler::resetBlock()
blockFinished = false;
}

std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx)
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx, int required_age_in_secs)
{
int64_t nTimeStart = GetTimeMicros();

Expand Down Expand Up @@ -172,7 +172,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
//addPriorityTxs(); addPackageTxs will take anything at any rate
int nPackagesSelected = 0;
int nDescendantsUpdated = 0;
addPackageTxs(nPackagesSelected, nDescendantsUpdated);
addPackageTxs(nPackagesSelected, nDescendantsUpdated, required_age_in_secs);

int64_t nTime1 = GetTimeMicros();

Expand Down Expand Up @@ -416,8 +416,9 @@ void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, CTxMemP
// Each time through the loop, we compare the best transaction in
// mapModifiedTxs with the next transaction in the mempool to decide what
// transaction package to work on next.
void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated)
void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, int required_age_in_secs)
{
int64_t current_time = GetTime();
// mapModifiedTx will store sorted packages after they are modified
// because some of their txs are already in the block
indexed_modified_transaction_set mapModifiedTx;
Expand Down Expand Up @@ -472,16 +473,19 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
}
}

// Skip transactions that are under X seconds in mempool
if (iter->GetTime() > current_time - required_age_in_secs) {
continue;
}

// We skip mapTx entries that are inBlock, and mapModifiedTx shouldn't
// contain anything that is inBlock.
assert(!inBlock.count(iter));

uint64_t packageSize = iter->GetSizeWithAncestors();
CAmount packageFees = iter->GetModFeesWithAncestors();
int64_t packageSigOpsCost = iter->GetSigOpCostWithAncestors();
if (fUsingModified) {
packageSize = modit->nSizeWithAncestors;
packageFees = modit->nModFeesWithAncestors;
packageSigOpsCost = modit->nSigOpCostWithAncestors;
}

Expand Down
4 changes: 2 additions & 2 deletions src/miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class BlockAssembler
public:
BlockAssembler(const CChainParams& chainparams);
/** Construct a new block template with coinbase to scriptPubKeyIn */
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx=true);
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx=true, int required_age_in_secs=0);

private:
// utility functions
Expand All @@ -180,7 +180,7 @@ class BlockAssembler
/** Add transactions based on feerate including unconfirmed ancestors
* Increments nPackagesSelected / nDescendantsUpdated with corresponding
* statistics from the package selection (for logging statistics). */
void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated);
void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, int required_age_in_secs=0);

// helper function for addPriorityTxs
/** Test if tx will still "fit" in the block */
Expand Down
1 change: 1 addition & 0 deletions src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "bumpfee", 1, "options" },
{ "testproposedblock", 1, "acceptnonstd" },
{ "sendtomainchain", 2, "subtractfeefromamount"},
{ "getnewblockhex", 0, "required_age"},
// Echo with conversion (For testing only)
{ "echojson", 0, "arg0" },
{ "echojson", 1, "arg1" },
Expand Down
13 changes: 10 additions & 3 deletions src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,19 +162,26 @@ UniValue generate(const JSONRPCRequest& request)

UniValue getnewblockhex(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
if (request.fHelp || request.params.size() > 1)
throw runtime_error(
"getnewblockhex\n"
"\nGets hex representation of a proposed, unmined new block\n"
"\nArguments:\n"
"1. required_age (numeric, optional, default=0) How many seconds a transaction must have been in the mempool to be inluded in the block proposal. This may help with faster block convergence among functionaries using compact blocks.\n"
"\nResult\n"
"blockhex (hex) The block hex\n"
"\nExamples:\n"
+ HelpExampleCli("getnewblockhex", "")
);

int required_wait = !request.params[0].isNull() ? request.params[0].get_int() : 0;
if (required_wait < 0) {
throw JSONRPCError(RPC_INVALID_PARAMS, "required_wait must be non-negative.");
}

CScript feeDestinationScript = Params().GetConsensus().mandatory_coinbase_destination;
if (feeDestinationScript == CScript()) feeDestinationScript = CScript() << OP_TRUE;
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(feeDestinationScript));
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(feeDestinationScript, true, required_wait));
if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty");
{
Expand Down Expand Up @@ -1012,7 +1019,7 @@ static const CRPCCommand commands[] =

{ "generating", "generate", &generate, true, {"nblocks","maxtries"} },
{ "generating", "combineblocksigs", &combineblocksigs, true, {} },
{ "generating", "getnewblockhex", &getnewblockhex, true, {} },
{ "generating", "getnewblockhex", &getnewblockhex, true, {"required_age"} },

{ "util", "estimatefee", &estimatefee, true, {"nblocks"} },
{ "util", "estimatepriority", &estimatepriority, true, {"nblocks"} },
Expand Down

0 comments on commit ed121e8

Please sign in to comment.