diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -12,6 +12,8 @@ static const uint64_t ONE_MEGABYTE = 1000000; /** The maximum allowed size for a transaction, in bytes */ static const uint64_t MAX_TX_SIZE = ONE_MEGABYTE; +/** The minimum allowed size for a transaction, in bytes */ +static const uint64_t MIN_TX_SIZE = 100; /** The maximum allowed size for a block, before the UAHF */ static const uint64_t LEGACY_MAX_BLOCK_SIZE = ONE_MEGABYTE; /** Default setting for maximum allowed size for a block, in bytes */ diff --git a/src/miner.h b/src/miner.h --- a/src/miner.h +++ b/src/miner.h @@ -146,6 +146,7 @@ // Chain context for the block int nHeight; int64_t nLockTimeCutoff; + int64_t nMedianTimePast; const Config *config; diff --git a/src/miner.cpp b/src/miner.cpp --- a/src/miner.cpp +++ b/src/miner.cpp @@ -162,9 +162,10 @@ pblock->nTime = GetAdjustedTime(); nMaxGeneratedBlockSize = ComputeMaxGeneratedBlockSize(*config, pindexPrev); + nMedianTimePast = pindexPrev->GetMedianTimePast(); nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) - ? pindexPrev->GetMedianTimePast() + ? nMedianTimePast : pblock->GetBlockTime(); addPriorityTxs(); @@ -196,6 +197,15 @@ coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus()); coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0; + + // Make sure the coinbase is big enough. + uint64_t coinbaseSize = + ::GetSerializeSize(coinbaseTx, SER_NETWORK, PROTOCOL_VERSION); + if (coinbaseSize < MIN_TX_SIZE) { + coinbaseTx.vin[0].scriptSig + << std::vector(MIN_TX_SIZE - coinbaseSize - 1); + } + pblock->vtx[0] = MakeTransactionRef(coinbaseTx); pblocktemplate->vTxFees[0] = -1 * nFees; @@ -278,7 +288,7 @@ for (const CTxMemPool::txiter it : package) { CValidationState state; if (!ContextualCheckTransaction(*config, it->GetTx(), state, nHeight, - nLockTimeCutoff)) { + nLockTimeCutoff, nMedianTimePast)) { return false; } @@ -330,7 +340,7 @@ // is always enforced as long as reorgs keep the mempool consistent. CValidationState state; if (!ContextualCheckTransaction(*config, it->GetTx(), state, nHeight, - nLockTimeCutoff)) { + nLockTimeCutoff, nMedianTimePast)) { return TestForBlockResult::TXCantFit; } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers +// Copyright (c) 2017-2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -285,8 +286,12 @@ txCoinbase.vout.resize(1); txCoinbase.vout[0].scriptPubKey = CScript(); pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase)); - if (txFirst.size() == 0) baseheight = chainActive.Height(); - if (txFirst.size() < 4) txFirst.push_back(pblock->vtx[0]); + if (txFirst.size() == 0) { + baseheight = chainActive.Height(); + } + if (txFirst.size() < 4) { + txFirst.push_back(pblock->vtx[0]); + } pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = blockinfo[i].nonce; std::shared_ptr shared_pblock = @@ -615,9 +620,10 @@ // Locktime passes on 2nd block. GlobalConfig config; CValidationState state; + int64_t nMedianTimePast = chainActive.Tip()->GetMedianTimePast(); BOOST_CHECK(ContextualCheckTransaction( config, CTransaction(tx), state, chainActive.Tip()->nHeight + 2, - chainActive.Tip()->GetMedianTimePast())); + nMedianTimePast, nMedianTimePast)); } // Absolute time locked. @@ -644,9 +650,10 @@ // Locktime passes 1 second later. GlobalConfig config; CValidationState state; + int64_t nMedianTimePast = chainActive.Tip()->GetMedianTimePast() + 1; BOOST_CHECK(ContextualCheckTransaction( config, CTransaction(tx), state, chainActive.Tip()->nHeight + 1, - chainActive.Tip()->GetMedianTimePast() + 1)); + nMedianTimePast, nMedianTimePast)); } // mempool-dependent transactions (not added) diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers +// Copyright (c) 2017-2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -6,8 +7,10 @@ #include "data/tx_valid.json.h" #include "test/test_bitcoin.h" +#include "chainparams.h" // For CChainParams #include "checkqueue.h" #include "clientversion.h" +#include "config.h" #include "consensus/validation.h" #include "core_io.h" #include "key.h" @@ -20,7 +23,7 @@ #include "test/jsonutil.h" #include "test/scriptflags.h" #include "utilstrencodings.h" -#include "validation.h" // For CheckRegularTransaction +#include "validation.h" // For CheckRegularTransaction and ContextualCheckTransaction #include #include @@ -757,4 +760,21 @@ BOOST_CHECK(!IsStandardTx(CTransaction(t), reason)); } +BOOST_AUTO_TEST_CASE(txsize_activation_test) { + const Config &config = GetConfig(); + const int64_t magneticAnomalyActivationTime = + config.GetChainParams().GetConsensus().magneticAnomalyActivationTime; + + // A minimaly sized transction. + CTransaction minTx; + CValidationState state; + + BOOST_CHECK(ContextualCheckTransaction(config, minTx, state, 1234, 5678, + magneticAnomalyActivationTime - 1)); + BOOST_CHECK(!ContextualCheckTransaction(config, minTx, state, 1234, 5678, + magneticAnomalyActivationTime)); + BOOST_CHECK_EQUAL(state.GetRejectCode(), REJECT_INVALID); + BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-undersize"); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -644,7 +644,8 @@ */ bool ContextualCheckTransaction(const Config &config, const CTransaction &tx, CValidationState &state, int nHeight, - int64_t nLockTimeCutoff); + int64_t nLockTimeCutoff, + int64_t nMedianTimePast); /** * This is a variant of ContextualCheckTransaction which computes the contextual diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3617,7 +3617,8 @@ bool ContextualCheckTransaction(const Config &config, const CTransaction &tx, CValidationState &state, int nHeight, - int64_t nLockTimeCutoff) { + int64_t nLockTimeCutoff, + int64_t nMedianTimePast) { if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { // While this is only one transaction, we use txns in the error to // ensure continuity with other clients. @@ -3625,6 +3626,14 @@ "non-final transaction"); } + if (IsMagneticAnomalyEnabled(config, nMedianTimePast)) { + // Size limit + if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) < + MIN_TX_SIZE) { + return state.DoS(100, false, REJECT_INVALID, "bad-txns-undersize"); + } + } + return true; } @@ -3654,12 +3663,15 @@ // When the next block is created its previous block will be the current // chain tip, so we use that to calculate the median time passed to // ContextualCheckTransaction() if LOCKTIME_MEDIAN_TIME_PAST is set. + const int64_t nMedianTimePast = + chainActive.Tip() == nullptr ? 0 + : chainActive.Tip()->GetMedianTimePast(); const int64_t nLockTimeCutoff = (flags & LOCKTIME_MEDIAN_TIME_PAST) - ? chainActive.Tip()->GetMedianTimePast() + ? nMedianTimePast : GetAdjustedTime(); return ContextualCheckTransaction(config, tx, state, nBlockHeight, - nLockTimeCutoff); + nLockTimeCutoff, nMedianTimePast); } static bool ContextualCheckBlock(const Config &config, const CBlock &block, @@ -3704,7 +3716,7 @@ } if (!ContextualCheckTransaction(config, tx, state, nHeight, - nLockTimeCutoff)) { + nLockTimeCutoff, nMedianTimePast)) { // state set by ContextualCheckTransaction. return false; } diff --git a/test/functional/abc-transaction-ordering.py b/test/functional/abc-magnetic-anomaly-activation.py copy from test/functional/abc-transaction-ordering.py copy to test/functional/abc-magnetic-anomaly-activation.py --- a/test/functional/abc-transaction-ordering.py +++ b/test/functional/abc-magnetic-anomaly-activation.py @@ -1,20 +1,17 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2016 The Bitcoin Core developers -# Copyright (c) 2017 The Bitcoin developers +# Copyright (c) 2018 The Bitcoin developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """ -This test checks that the nod esoftware accepts transactions in -non topological order once the feature is activated. +This test checks that simple features of the magnetic anomaly fork +activates properly. More complex features are given their own tests. """ from test_framework.test_framework import ComparisonTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error from test_framework.comptool import TestManager, TestInstance, RejectResult from test_framework.blocktools import * -import time -from test_framework.key import CECKey -from test_framework.script import * +from test_framework.cdefs import MIN_TX_SIZE from collections import deque # far into the future @@ -28,11 +25,7 @@ self.n = n # the output we're spending -class TransactionOrderingTest(ComparisonTestFramework): - - # Can either run this test as 1 node with expected answers, or two and compare them. - # Change the "outcome" variable from each TestInstance object to only do - # the comparison. +class MagneticAnomalyActivationTest(ComparisonTestFramework): def set_test_params(self): self.num_nodes = 1 @@ -57,12 +50,7 @@ [tx.rehash() for tx in tx_list] block.vtx.extend(tx_list) - # this is a little handier to use than the version in blocktools.py - def create_tx(self, spend, value, script=CScript([OP_TRUE])): - tx = create_transaction(spend.tx, spend.n, b"", value, script) - return tx - - def next_block(self, number, spend=None, tx_count=0): + def next_block(self, number, spend=None, tx_size=0): if self.tip == None: base_block_hash = self.genesis_hash block_time = int(time.time()) + 1 @@ -85,45 +73,35 @@ # Make sure we have plenty enough to spend going forward. spendable_outputs = deque([spend]) - def get_base_transaction(): - # Create the new transaction - tx = CTransaction() - # Spend from one of the spendable outputs - spend = spendable_outputs.popleft() - tx.vin.append(CTxIn(COutPoint(spend.tx.sha256, spend.n))) - # Add spendable outputs - for i in range(4): - tx.vout.append(CTxOut(0, CScript([OP_TRUE]))) - spendable_outputs.append(PreviousSpendableOutput(tx, i)) - return tx - - tx = get_base_transaction() + # Create the new transaction + tx = CTransaction() + # Spend from one of the spendable outputs + spend = spendable_outputs.popleft() + tx.vin.append(CTxIn(COutPoint(spend.tx.sha256, spend.n))) + # Add spendable outputs + for i in range(2): + tx.vout.append(CTxOut(0, CScript([OP_TRUE]))) + spendable_outputs.append(PreviousSpendableOutput(tx, i)) + # Put some random data into the transaction in order to randomize ids. + if tx_size == 0: + tx.vout.append( + CTxOut(0, CScript([random.getrandbits(8), OP_RETURN]))) + else: + tx.vout.append( + CTxOut(0, CScript([random.getrandbits(8 * (tx_size - 82) - 1), OP_RETURN]))) + assert_equal(len(tx.serialize()), tx_size) # Make it the same format as transaction added for padding and save the size. # It's missing the padding output, so we add a constant to account for it. tx.rehash() - base_tx_size = len(tx.serialize()) + 18 - - # Put some random data into the first transaction of the chain to randomize ids. - tx.vout.append( - CTxOut(0, CScript([random.randint(0, 256), OP_RETURN]))) # Add the transaction to the block self.add_transactions_to_block(block, [tx]) - # If we have a transaction count requirement, just fill the block until we get there - while len(block.vtx) < tx_count: - # Create the new transaction and add it. - tx = get_base_transaction() - self.add_transactions_to_block(block, [tx]) - # Now that we added a bunch of transaction, we need to recompute # the merkle root. block.hashMerkleRoot = block.calc_merkle_root() - if tx_count > 0: - assert_equal(len(block.vtx), tx_count) - # Do PoW, which is cheap on regnet block.solve() self.tip = block @@ -219,50 +197,29 @@ assert_equal(node.getblockheader(node.getbestblockhash())['mediantime'], MAGNETIC_ANOMALY_START_TIME - 1) - # Before we activate the Nov 15, 2018 HF, transaction order is respected. - def ordered_block(block_number, spend): - b = block(block_number, spend=spend, tx_count=16) - b.vtx = [b.vtx[0]] + sorted(b.vtx[1:], key=lambda tx: tx.get_id()) - update_block(block_number) - return b - - ordered_block(4444, out[16]) - yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) - - # Rewind bad block. - tip(5104) - - # Activate the Nov 15, 2018 HF - block(5556, out[16], tx_count=16) + # Check that block with small transactions are still accepted. + small_tx_block = block(4444, out[0], MIN_TX_SIZE - 1) + assert_equal(len(small_tx_block.vtx[1].serialize()), MIN_TX_SIZE - 1) yield accepted() - # Now MTP is exactly the fork time. Bigger blocks are now accepted. + # Now MTP is exactly the fork time. Small transaction are now rejected. assert_equal(node.getblockheader(node.getbestblockhash())['mediantime'], MAGNETIC_ANOMALY_START_TIME) - # Block with regular ordering are now rejected. - block(5557, out[17], tx_count=16) - yield rejected(RejectResult(16, b'tx-ordering')) + # Now that the for activated, it is not possible to have + # small transactions anymore. + small_tx_block = block(4445, out[1], MIN_TX_SIZE - 1) + assert_equal(len(small_tx_block.vtx[1].serialize()), MIN_TX_SIZE - 1) + yield rejected(RejectResult(16, b'bad-txns-undersize')) # Rewind bad block. - tip(5556) + tip(4444) - # Now that the fork activated, we need to order transaction per txid. - ordered_block(4445, out[17]) + # But large transactions are still ok. + large_tx_block = block(4446, out[1], MIN_TX_SIZE) + assert_equal(len(large_tx_block.vtx[1].serialize()), MIN_TX_SIZE) yield accepted() - # Invalidate the best block and make sure we are back at the fork point. - ctorblockhash = node.getbestblockhash() - node.invalidateblock(ctorblockhash) - forkblockhash = node.getbestblockhash() - assert(forkblockhash != ctorblockhash) - assert_equal(node.getblockheader(forkblockhash)[ - 'mediantime'], MAGNETIC_ANOMALY_START_TIME) - - node.generate(1) - generatedblockhash = node.getbestblockhash() - assert(forkblockhash != generatedblockhash) - if __name__ == '__main__': - TransactionOrderingTest().main() + MagneticAnomalyActivationTest().main() diff --git a/test/functional/abc-transaction-ordering.py b/test/functional/abc-transaction-ordering.py --- a/test/functional/abc-transaction-ordering.py +++ b/test/functional/abc-transaction-ordering.py @@ -1,10 +1,9 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2016 The Bitcoin Core developers -# Copyright (c) 2017 The Bitcoin developers +# Copyright (c) 2018 The Bitcoin developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """ -This test checks that the nod esoftware accepts transactions in +This test checks that the node software accepts transactions in non topological order once the feature is activated. """ @@ -57,11 +56,6 @@ [tx.rehash() for tx in tx_list] block.vtx.extend(tx_list) - # this is a little handier to use than the version in blocktools.py - def create_tx(self, spend, value, script=CScript([OP_TRUE])): - tx = create_transaction(spend.tx, spend.n, b"", value, script) - return tx - def next_block(self, number, spend=None, tx_count=0): if self.tip == None: base_block_hash = self.genesis_hash @@ -95,6 +89,10 @@ for i in range(4): tx.vout.append(CTxOut(0, CScript([OP_TRUE]))) spendable_outputs.append(PreviousSpendableOutput(tx, i)) + # Put some random data into the transaction in order to randomize ids. + # This also ensures that transaction are larger than 100 bytes. + tx.vout.append( + CTxOut(0, CScript([random.getrandbits(256), OP_RETURN]))) return tx tx = get_base_transaction() @@ -102,11 +100,6 @@ # Make it the same format as transaction added for padding and save the size. # It's missing the padding output, so we add a constant to account for it. tx.rehash() - base_tx_size = len(tx.serialize()) + 18 - - # Put some random data into the first transaction of the chain to randomize ids. - tx.vout.append( - CTxOut(0, CScript([random.randint(0, 256), OP_RETURN]))) # Add the transaction to the block self.add_transactions_to_block(block, [tx]) @@ -236,7 +229,7 @@ block(5556, out[16], tx_count=16) yield accepted() - # Now MTP is exactly the fork time. Bigger blocks are now accepted. + # Now MTP is exactly the fork time. Transactions are expected to be ordered now. assert_equal(node.getblockheader(node.getbestblockhash())['mediantime'], MAGNETIC_ANOMALY_START_TIME) diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py --- a/test/functional/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py @@ -60,6 +60,12 @@ else: coinbaseoutput.scriptPubKey = CScript([OP_TRUE]) coinbase.vout = [coinbaseoutput] + + # Make sure the coinbase is at least 100 bytes + coinbase_size = len(coinbase.serialize()) + if coinbase_size < 100: + coinbase.vin[0].scriptSig += b'x' * (100 - coinbase_size) + coinbase.calc_sha256() return coinbase diff --git a/test/functional/test_framework/cdefs.py b/test/functional/test_framework/cdefs.py --- a/test/functional/test_framework/cdefs.py +++ b/test/functional/test_framework/cdefs.py @@ -85,8 +85,8 @@ # blocks (network rule) COINBASE_MATURITY = 100 -# Anti replay OP_RETURN commitment. -ANTI_REPLAY_COMMITMENT = b"Bitcoin: A Peer-to-Peer Electronic Cash System" +# Minimum size a transaction can have. +MIN_TX_SIZE = 100 if __name__ == "__main__": # Output values if run standalone to verify diff --git a/test/functional/timing.json b/test/functional/timing.json --- a/test/functional/timing.json +++ b/test/functional/timing.json @@ -1,27 +1,31 @@ [ { "name": "abandonconflict.py", - "time": 14 + "time": 17 }, { "name": "abc-cmdline.py", - "time": 9 + "time": 8 }, { "name": "abc-high_priority_transaction.py", - "time": 11 + "time": 10 + }, + { + "name": "abc-magnetic-anomaly-activation.py", + "time": 15 }, { "name": "abc-mempool-accept-txn.py", - "time": 4 + "time": 5 }, { "name": "abc-p2p-compactblocks.py", - "time": 194 + "time": 176 }, { "name": "abc-p2p-fullblocktest.py", - "time": 77 + "time": 51 }, { "name": "abc-replay-protection.py", @@ -33,27 +37,27 @@ }, { "name": "abc-transaction-ordering.py", - "time": 7 + "time": 13 }, { "name": "assumevalid.py", - "time": 14 + "time": 13 }, { "name": "bip65-cltv-p2p.py", - "time": 6 + "time": 7 }, { "name": "bip68-112-113-p2p.py", - "time": 21 + "time": 22 }, { "name": "bip68-sequence.py", - "time": 36 + "time": 40 }, { "name": "bipdersig-p2p.py", - "time": 6 + "time": 18 }, { "name": "bitcoin_cli.py", @@ -61,15 +65,15 @@ }, { "name": "blockchain.py", - "time": 9 + "time": 19 }, { "name": "dbcrash.py", - "time": 923 + "time": 1183 }, { "name": "decodescript.py", - "time": 3 + "time": 4 }, { "name": "disablewallet.py", @@ -77,11 +81,11 @@ }, { "name": "disconnect_ban.py", - "time": 16 + "time": 24 }, { "name": "example_test.py", - "time": 14 + "time": 4 }, { "name": "forknotify.py", @@ -89,23 +93,23 @@ }, { "name": "fundrawtransaction.py", - "time": 41 + "time": 43 }, { "name": "getblocktemplate_longpoll.py", - "time": 69 + "time": 68 }, { "name": "getchaintips.py", - "time": 5 + "time": 7 }, { "name": "httpbasics.py", - "time": 3 + "time": 6 }, { "name": "import-rescan.py", - "time": 32 + "time": 20 }, { "name": "importmulti.py", @@ -113,11 +117,11 @@ }, { "name": "importprunedfunds.py", - "time": 3 + "time": 4 }, { "name": "invalidateblock.py", - "time": 8 + "time": 21 }, { "name": "invalidblockrequest.py", @@ -129,23 +133,23 @@ }, { "name": "keypool-topup.py", - "time": 26 + "time": 23 }, { "name": "keypool.py", - "time": 31 + "time": 11 }, { "name": "listsinceblock.py", - "time": 9 + "time": 5 }, { "name": "listtransactions.py", - "time": 11 + "time": 12 }, { "name": "maxuploadtarget.py", - "time": 53 + "time": 52 }, { "name": "mempool_limit.py", @@ -153,15 +157,15 @@ }, { "name": "mempool_packages.py", - "time": 60 + "time": 30 }, { "name": "mempool_persist.py", - "time": 19 + "time": 27 }, { "name": "mempool_reorg.py", - "time": 6 + "time": 5 }, { "name": "mempool_resurrect_test.py", @@ -169,19 +173,19 @@ }, { "name": "mempool_spendcoinbase.py", - "time": 3 + "time": 2 }, { "name": "merkle_blocks.py", - "time": 4 + "time": 5 }, { "name": "minchainwork.py", - "time": 16 + "time": 6 }, { "name": "mining.py", - "time": 4 + "time": 3 }, { "name": "multi_rpc.py", @@ -189,39 +193,39 @@ }, { "name": "multiwallet.py", - "time": 10 + "time": 7 }, { "name": "net.py", - "time": 4 + "time": 5 }, { "name": "nulldummy.py", - "time": 15 + "time": 3 }, { "name": "p2p-acceptblock.py", - "time": 7 + "time": 8 }, { "name": "p2p-compactblocks.py", - "time": 25 + "time": 27 }, { "name": "p2p-feefilter.py", - "time": 22 + "time": 31 }, { "name": "p2p-fullblocktest.py", - "time": 136 + "time": 140 }, { "name": "p2p-leaktests.py", - "time": 13 + "time": 8 }, { "name": "p2p-mempool.py", - "time": 13 + "time": 3 }, { "name": "p2p-timeouts.py", @@ -229,27 +233,27 @@ }, { "name": "preciousblock.py", - "time": 4 + "time": 5 }, { "name": "prioritise_transaction.py", - "time": 11 + "time": 22 }, { "name": "proxy_test.py", - "time": 5 + "time": 4 }, { "name": "pruning.py", - "time": 1387 + "time": 1623 }, { "name": "rawtransactions.py", - "time": 17 + "time": 15 }, { "name": "receivedby.py", - "time": 11 + "time": 21 }, { "name": "reindex.py", @@ -257,27 +261,27 @@ }, { "name": "resendwallettransactions.py", - "time": 6 + "time": 18 }, { "name": "rest.py", - "time": 9 + "time": 19 }, { "name": "rpcbind_test.py", - "time": 27 + "time": 28 }, { "name": "rpcnamedargs.py", - "time": 25 + "time": 3 }, { "name": "sendheaders.py", - "time": 27 + "time": 29 }, { "name": "signmessages.py", - "time": 12 + "time": 2 }, { "name": "signrawtransactions.py", @@ -285,7 +289,7 @@ }, { "name": "txn_clone.py", - "time": 5 + "time": 6 }, { "name": "txn_clone.py --mineblock", @@ -293,7 +297,7 @@ }, { "name": "txn_doublespend.py", - "time": 27 + "time": 20 }, { "name": "txn_doublespend.py --mineblock", @@ -301,38 +305,38 @@ }, { "name": "uptime.py", - "time": 3 + "time": 2 }, { "name": "wallet-accounts.py", - "time": 8 + "time": 15 }, { "name": "wallet-dump.py", - "time": 11 + "time": 8 }, { "name": "wallet-encryption.py", - "time": 9 + "time": 24 }, { "name": "wallet-hd.py", - "time": 107 + "time": 82 }, { "name": "wallet.py", - "time": 45 + "time": 43 }, { "name": "walletbackup.py", - "time": 110 + "time": 139 }, { "name": "zapwallettxes.py", - "time": 15 + "time": 12 }, { "name": "zmq_test.py", - "time": 5 + "time": 4 } -] +] \ No newline at end of file