diff --git a/qa/rpc-tests/bip68-112-113-p2p.py b/qa/rpc-tests/bip68-112-113-p2p.py index f391cb0b7a..35c831cb8b 100755 --- a/qa/rpc-tests/bip68-112-113-p2p.py +++ b/qa/rpc-tests/bip68-112-113-p2p.py @@ -149,13 +149,6 @@ class BIP68_112_113Test(ComparisonTestFramework): block.solve() return block - def get_bip9_status(self, key): - info = self.nodes[0].getblockchaininfo() - for row in info['bip9_softforks']: - if row['id'] == key: - return row - raise IndexError ('key:"%s" not found' % key) - def create_bip68txs(self, bip68inputs, txversion, locktime_delta = 0): txs = [] assert(len(bip68inputs) >= 16) @@ -223,11 +216,11 @@ class BIP68_112_113Test(ComparisonTestFramework): self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) self.nodeaddress = self.nodes[0].getnewaddress() - assert_equal(self.get_bip9_status('csv')['status'], 'defined') + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'defined') test_blocks = self.generate_blocks(61, 4) yield TestInstance(test_blocks, sync_every_block=False) # 1 # Advanced from DEFINED to STARTED, height = 143 - assert_equal(self.get_bip9_status('csv')['status'], 'started') + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') # Fail to achieve LOCKED_IN 100 out of 144 signal bit 0 # using a variety of bits to simulate multiple parallel softforks @@ -237,7 +230,7 @@ class BIP68_112_113Test(ComparisonTestFramework): test_blocks = self.generate_blocks(24, 536936448, test_blocks) # 0x20010000 (signalling not) yield TestInstance(test_blocks, sync_every_block=False) # 2 # Failed to advance past STARTED, height = 287 - assert_equal(self.get_bip9_status('csv')['status'], 'started') + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') # 108 out of 144 signal bit 0 to achieve lock-in # using a variety of bits to simulate multiple parallel softforks @@ -247,7 +240,7 @@ class BIP68_112_113Test(ComparisonTestFramework): test_blocks = self.generate_blocks(10, 536936448, test_blocks) # 0x20010000 (signalling not) yield TestInstance(test_blocks, sync_every_block=False) # 3 # Advanced from STARTED to LOCKED_IN, height = 431 - assert_equal(self.get_bip9_status('csv')['status'], 'locked_in') + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') # 140 more version 4 blocks test_blocks = self.generate_blocks(140, 4) @@ -291,7 +284,7 @@ class BIP68_112_113Test(ComparisonTestFramework): test_blocks = self.generate_blocks(2, 4) yield TestInstance(test_blocks, sync_every_block=False) # 5 # Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575) - assert_equal(self.get_bip9_status('csv')['status'], 'locked_in') + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') # Test both version 1 and version 2 transactions for all tests # BIP113 test transaction will be modified before each use to put in appropriate block time @@ -368,7 +361,7 @@ class BIP68_112_113Test(ComparisonTestFramework): # 1 more version 4 block to get us to height 575 so the fork should now be active for the next block test_blocks = self.generate_blocks(1, 4) yield TestInstance(test_blocks, sync_every_block=False) # 8 - assert_equal(self.get_bip9_status('csv')['status'], 'active') + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'active') ################################# diff --git a/qa/rpc-tests/bip68-sequence.py b/qa/rpc-tests/bip68-sequence.py index 377a35b687..33e05dfc51 100755 --- a/qa/rpc-tests/bip68-sequence.py +++ b/qa/rpc-tests/bip68-sequence.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. # -# Test BIP68 implementation (mempool only) +# Test BIP68 implementation # from test_framework.test_framework import BitcoinTestFramework @@ -26,8 +26,10 @@ class BIP68Test(BitcoinTestFramework): def setup_network(self): self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-blockprioritysize=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-blockprioritysize=0", "-acceptnonstdtxn=0"])) self.is_network_split = False self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"] + connect_nodes(self.nodes[0], 1) def run_test(self): # Generate some coins @@ -42,10 +44,18 @@ class BIP68Test(BitcoinTestFramework): print "Running test sequence-lock-unconfirmed-inputs" self.test_sequence_lock_unconfirmed_inputs() - # This test needs to change when BIP68 becomes consensus - print "Running test BIP68 not consensus" + print "Running test BIP68 not consensus before versionbits activation" self.test_bip68_not_consensus() + print "Verifying nVersion=2 transactions aren't standard" + self.test_version2_relay(before_activation=True) + + print "Activating BIP68 (and 112/113)" + self.activateCSV() + + print "Verifying nVersion=2 transactions are now standard" + self.test_version2_relay(before_activation=False) + print "Passed\n" # Test that BIP68 is not in effect if tx version is 1, or if @@ -333,8 +343,12 @@ class BIP68Test(BitcoinTestFramework): self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height+1)) self.nodes[0].generate(10) - # Make sure that BIP68 isn't being used to validate blocks. + # Make sure that BIP68 isn't being used to validate blocks, prior to + # versionbits activation. If more blocks are mined prior to this test + # being run, then it's possible the test has activated the soft fork, and + # this test should be moved to run earlier, or deleted. def test_bip68_not_consensus(self): + assert(get_bip9_status(self.nodes[0], 'csv')['status'] != 'active') txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2) tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid)) @@ -381,6 +395,30 @@ class BIP68Test(BitcoinTestFramework): self.nodes[0].submitblock(ToHex(block)) assert_equal(self.nodes[0].getbestblockhash(), block.hash) + def activateCSV(self): + # activation should happen at block height 432 (3 periods) + min_activation_height = 432 + height = self.nodes[0].getblockcount() + assert(height < 432) + self.nodes[0].generate(432-height) + assert(get_bip9_status(self.nodes[0], 'csv')['status'] == 'active') + sync_blocks(self.nodes) + + # Use self.nodes[1] to test standardness relay policy + def test_version2_relay(self, before_activation): + inputs = [ ] + outputs = { self.nodes[1].getnewaddress() : 1.0 } + rawtx = self.nodes[1].createrawtransaction(inputs, outputs) + rawtxfund = self.nodes[1].fundrawtransaction(rawtx)['hex'] + tx = FromHex(CTransaction(), rawtxfund) + tx.nVersion = 2 + tx_signed = self.nodes[1].signrawtransaction(ToHex(tx))["hex"] + try: + tx_id = self.nodes[1].sendrawtransaction(tx_signed) + assert(before_activation == False) + except: + assert(before_activation) + if __name__ == '__main__': BIP68Test().main() diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index f069c32a60..d9fe0f75f2 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -545,3 +545,10 @@ def create_lots_of_big_transactions(node, txouts, utxos, fee): txid = node.sendrawtransaction(signresult["hex"], True) txids.append(txid) return txids + +def get_bip9_status(node, key): + info = node.getblockchaininfo() + for row in info['bip9_softforks']: + if row['id'] == key: + return row + raise IndexError ('key:"%s" not found' % key) diff --git a/src/main.cpp b/src/main.cpp index a9f104c88b..f5c7e11d6e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1025,6 +1025,14 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C if (fRequireStandard && !IsStandardTx(tx, reason)) return state.DoS(0, false, REJECT_NONSTANDARD, reason); + // Don't relay version 2 transactions until CSV is active, and we can be + // sure that such transactions will be mined (unless we're on + // -testnet/-regtest). + const CChainParams& chainparams = Params(); + if (fRequireStandard && tx.nVersion >= 2 && VersionBitsTipState(chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV) != THRESHOLD_ACTIVE) { + return state.DoS(0, false, REJECT_NONSTANDARD, "premature-version2-tx"); + } + // Only accept nLockTime-using transactions that can be mined in the next // block; we don't want our mempool filled up with transactions that can't // be mined yet.