Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc-block-sigchecks-activation.py
Show All 19 Lines | from test_framework.messages import ( | ||||
CTransaction, | CTransaction, | ||||
CTxIn, | CTxIn, | ||||
CTxOut, | CTxOut, | ||||
FromHex, | FromHex, | ||||
) | ) | ||||
from test_framework.mininode import P2PDataStore | from test_framework.mininode import P2PDataStore | ||||
from test_framework.script import ( | from test_framework.script import ( | ||||
CScript, | CScript, | ||||
OP_CHECKDATASIG, | |||||
OP_CHECKDATASIGVERIFY, | OP_CHECKDATASIGVERIFY, | ||||
OP_3DUP, | OP_3DUP, | ||||
OP_RETURN, | OP_RETURN, | ||||
OP_TRUE, | OP_TRUE, | ||||
) | ) | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.txtools import pad_tx | from test_framework.txtools import pad_tx | ||||
from test_framework.util import assert_equal | from test_framework.util import assert_equal | ||||
Show All 13 Lines | |||||
assert MAXBLOCKSIZE == 1127999 | assert MAXBLOCKSIZE == 1127999 | ||||
# Blocks with too many sigchecks from cache give this error in log file: | # Blocks with too many sigchecks from cache give this error in log file: | ||||
BLOCK_SIGCHECKS_CACHED_ERROR = "blk-bad-inputs, CheckInputs exceeded SigChecks limit" | BLOCK_SIGCHECKS_CACHED_ERROR = "blk-bad-inputs, CheckInputs exceeded SigChecks limit" | ||||
# Blocks with too many sigchecks discovered during parallel checks give | # Blocks with too many sigchecks discovered during parallel checks give | ||||
# this error in log file: | # this error in log file: | ||||
BLOCK_SIGCHECKS_PARALLEL_ERROR = "blk-bad-inputs, parallel script check failed" | BLOCK_SIGCHECKS_PARALLEL_ERROR = "blk-bad-inputs, parallel script check failed" | ||||
MAX_TX_SIGCHECK = 3000 | |||||
def create_transaction(spendfrom, custom_script, amount=None): | def create_transaction(spendfrom, custom_script, amount=None): | ||||
# Fund and sign a transaction to a given output. | # Fund and sign a transaction to a given output. | ||||
# spendfrom should be a CTransaction with first output to OP_TRUE. | # spendfrom should be a CTransaction with first output to OP_TRUE. | ||||
# custom output will go on position 1, after position 0 which will be | # custom output will go on position 1, after position 0 which will be | ||||
# OP_TRUE (so it can be reused). | # OP_TRUE (so it can be reused). | ||||
customout = CTxOut(0, bytes(custom_script)) | customout = CTxOut(0, bytes(custom_script)) | ||||
▲ Show 20 Lines • Show All 166 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
submittxes_2 = [] | submittxes_2 = [] | ||||
while len(usable_inputs) >= 100: | while len(usable_inputs) >= 100: | ||||
tx = CTransaction() | tx = CTransaction() | ||||
tx.vin = [usable_inputs.pop() for _ in range(100)] | tx.vin = [usable_inputs.pop() for _ in range(100)] | ||||
tx.vout = [CTxOut(0, CScript([OP_RETURN]))] | tx.vout = [CTxOut(0, CScript([OP_RETURN]))] | ||||
tx.rehash() | tx.rehash() | ||||
submittxes_2.append(tx) | submittxes_2.append(tx) | ||||
# Check high sigcheck transactions | |||||
self.log.info("Create transaction that have high sigchecks") | |||||
fundings = [] | |||||
def make_spend(sigcheckcount): | |||||
# Add a funding tx to fundings, and return a tx spending that using | |||||
# scriptsig. | |||||
self.log.debug( | |||||
"Gen tx with {} sigchecks.".format(sigcheckcount)) | |||||
def get_script_with_sigcheck(count): | |||||
return CScript([cds_message, | |||||
cds_pubkey] + (count - 1) * [OP_3DUP, OP_CHECKDATASIGVERIFY] + [OP_CHECKDATASIG]) | |||||
# get funds locked with OP_1 | |||||
sourcetx = self.spendable_outputs.popleft() | |||||
# make funding that forwards to scriptpubkey | |||||
last_sigcheck_count = ((sigcheckcount - 1) % 30) + 1 | |||||
fundtx = create_transaction( | |||||
sourcetx, get_script_with_sigcheck(last_sigcheck_count)) | |||||
fill_sigcheck_script = get_script_with_sigcheck(30) | |||||
remaining_sigcheck = sigcheckcount | |||||
while remaining_sigcheck > 30: | |||||
fundtx.vout[0].nValue -= 1000 | |||||
fundtx.vout.append(CTxOut(100, bytes(fill_sigcheck_script))) | |||||
remaining_sigcheck -= 30 | |||||
fundtx.rehash() | |||||
fundings.append(fundtx) | |||||
# make the spending | |||||
scriptsig = CScript([cds_signature]) | |||||
tx = CTransaction() | |||||
tx.vin.append(CTxIn(COutPoint(fundtx.sha256, 1), scriptsig)) | |||||
input_index = 2 | |||||
remaining_sigcheck = sigcheckcount | |||||
while remaining_sigcheck > 30: | |||||
tx.vin.append( | |||||
CTxIn( | |||||
COutPoint( | |||||
fundtx.sha256, | |||||
input_index), | |||||
scriptsig)) | |||||
remaining_sigcheck -= 30 | |||||
input_index += 1 | |||||
tx.vout.append(CTxOut(0, CScript([OP_RETURN]))) | |||||
pad_tx(tx) | |||||
tx.rehash() | |||||
return tx | |||||
# Create transactions with many sigchecks. | |||||
good_tx = make_spend(MAX_TX_SIGCHECK) | |||||
bad_tx = make_spend(MAX_TX_SIGCHECK + 1) | |||||
tip = self.build_block(tip, fundings) | |||||
node.p2p.send_blocks_and_test([tip], node) | |||||
# Both tx are accepted before the activation. | |||||
pre_activation_sigcheck_block = self.build_block( | |||||
tip, [good_tx, bad_tx]) | |||||
node.p2p.send_blocks_and_test([pre_activation_sigcheck_block], node) | |||||
node.invalidateblock(pre_activation_sigcheck_block.hash) | |||||
# Activation tests | # Activation tests | ||||
self.log.info("Approach to just before upgrade activation") | self.log.info("Approach to just before upgrade activation") | ||||
# Move our clock to the uprade time so we will accept such | # Move our clock to the uprade time so we will accept such | ||||
# future-timestamped blocks. | # future-timestamped blocks. | ||||
node.setmocktime(SIGCHECKS_ACTIVATION_TIME + 10) | node.setmocktime(SIGCHECKS_ACTIVATION_TIME + 10) | ||||
# Mine six blocks with timestamp starting at | # Mine six blocks with timestamp starting at | ||||
# SIGCHECKS_ACTIVATION_TIME-1 | # SIGCHECKS_ACTIVATION_TIME-1 | ||||
Show All 33 Lines | def run_test(self): | ||||
self.log.info("Mine the activation block itself") | self.log.info("Mine the activation block itself") | ||||
tip = self.build_block(tip) | tip = self.build_block(tip) | ||||
node.p2p.send_blocks_and_test([tip], node) | node.p2p.send_blocks_and_test([tip], node) | ||||
self.log.info("We have activated!") | self.log.info("We have activated!") | ||||
assert_equal(node.getblockchaininfo()[ | assert_equal(node.getblockchaininfo()[ | ||||
'mediantime'], SIGCHECKS_ACTIVATION_TIME) | 'mediantime'], SIGCHECKS_ACTIVATION_TIME) | ||||
self.log.info( | |||||
"Try a block with a transaction going over the limit (limit: {})".format(MAX_TX_SIGCHECK)) | |||||
bad_tx_block = self.build_block(tip, [bad_tx]) | |||||
check_for_ban_on_rejected_block( | |||||
node, bad_tx_block, reject_reason=BLOCK_SIGCHECKS_PARALLEL_ERROR) | |||||
self.log.info( | |||||
"Try a block with a transaction just under the limit (limit: {})".format(MAX_TX_SIGCHECK)) | |||||
good_tx_block = self.build_block(tip, [good_tx]) | |||||
node.p2p.send_blocks_and_test([good_tx_block], node) | |||||
node.invalidateblock(good_tx_block.hash) | |||||
# save this tip for later | # save this tip for later | ||||
# ~ upgrade_block = tip | # ~ upgrade_block = tip | ||||
# Transactions still in pool: | # Transactions still in pool: | ||||
assert_equal(set(node.getrawmempool()), {t.hash for t in submittxes_1}) | assert_equal(set(node.getrawmempool()), {t.hash for t in submittxes_1}) | ||||
self.log.info("Try sending 10000-sigcheck blocks after activation (limit: {})".format( | self.log.info("Try sending 10000-sigcheck blocks after activation (limit: {})".format( | ||||
MAXBLOCKSIZE // BLOCK_MAXBYTES_MAXSIGCHECKS_RATIO)) | MAXBLOCKSIZE // BLOCK_MAXBYTES_MAXSIGCHECKS_RATIO)) | ||||
▲ Show 20 Lines • Show All 60 Lines • Show Last 20 Lines |