Merge bitcoin/bitcoin#22378: test: remove confusing MAX_BLOCK_BASE_SIZE

607076d01b test: remove confusing `MAX_BLOCK_BASE_SIZE` (Sebastian Falbesoner)
4af97c74ed test: introduce `get_weight()` helper for CBlock (Sebastian Falbesoner)
a084ebe133 test: introduce `get_weight()` helper for CTransaction (Sebastian Falbesoner)

Pull request description:

  This is a very late follow-up PR to #10618, which removed the constant `MAX_BLOCK_BASE_SIZE` from the core implementation about four years ago (see also #10608 in why it was considered confusing and superfluous).
  Since there is also no point in still keeping it in the functional test framework, the PR switches to weight-based accounting on the relevant test code parts and use `MAX_BLOCK_WEIGHT` instead for the block limit checks. To prepare that, the first two commits introduce `get_weight()` helpers for the classes CTransaction and CBlock, respectively.

ACKs for top commit:
  MarcoFalke:
    review ACK 607076d01b 🚴

Tree-SHA512: d59aa0b6b3dfd0a849b8063e66de275d252f705f99e25cd3bf6daec028b47d946777ee5b42a060f5283cb18e917ac073119c2c0e11bbc21211f69ef0a6ed335a
This commit is contained in:
MarcoFalke 2021-08-02 15:51:42 +02:00
commit b620b2d58a
No known key found for this signature in database
GPG key ID: CE2B75697E69A548
6 changed files with 57 additions and 62 deletions

View file

@ -22,7 +22,7 @@ from test_framework.messages import (
CTransaction, CTransaction,
CTxIn, CTxIn,
CTxOut, CTxOut,
MAX_BLOCK_BASE_SIZE, MAX_BLOCK_WEIGHT,
uint256_from_compact, uint256_from_compact,
uint256_from_str, uint256_from_str,
) )
@ -307,33 +307,33 @@ class FullBlockTest(BitcoinTestFramework):
b22 = self.next_block(22, spend=out[5]) b22 = self.next_block(22, spend=out[5])
self.send_blocks([b22], success=False, reject_reason='bad-txns-premature-spend-of-coinbase', reconnect=True) self.send_blocks([b22], success=False, reject_reason='bad-txns-premature-spend-of-coinbase', reconnect=True)
# Create a block on either side of MAX_BLOCK_BASE_SIZE and make sure its accepted/rejected # Create a block on either side of MAX_BLOCK_WEIGHT and make sure its accepted/rejected
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
# \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6)
# \-> b24 (6) -> b25 (7) # \-> b24 (6) -> b25 (7)
# \-> b3 (1) -> b4 (2) # \-> b3 (1) -> b4 (2)
self.log.info("Accept a block of size MAX_BLOCK_BASE_SIZE") self.log.info("Accept a block of weight MAX_BLOCK_WEIGHT")
self.move_tip(15) self.move_tip(15)
b23 = self.next_block(23, spend=out[6]) b23 = self.next_block(23, spend=out[6])
tx = CTransaction() tx = CTransaction()
script_length = MAX_BLOCK_BASE_SIZE - len(b23.serialize()) - 69 script_length = (MAX_BLOCK_WEIGHT - b23.get_weight() - 276) // 4
script_output = CScript([b'\x00' * script_length]) script_output = CScript([b'\x00' * script_length])
tx.vout.append(CTxOut(0, script_output)) tx.vout.append(CTxOut(0, script_output))
tx.vin.append(CTxIn(COutPoint(b23.vtx[1].sha256, 0))) tx.vin.append(CTxIn(COutPoint(b23.vtx[1].sha256, 0)))
b23 = self.update_block(23, [tx]) b23 = self.update_block(23, [tx])
# Make sure the math above worked out to produce a max-sized block # Make sure the math above worked out to produce a max-weighted block
assert_equal(len(b23.serialize()), MAX_BLOCK_BASE_SIZE) assert_equal(b23.get_weight(), MAX_BLOCK_WEIGHT)
self.send_blocks([b23], True) self.send_blocks([b23], True)
self.save_spendable_output() self.save_spendable_output()
self.log.info("Reject a block of size MAX_BLOCK_BASE_SIZE + 1") self.log.info("Reject a block of weight MAX_BLOCK_WEIGHT + 4")
self.move_tip(15) self.move_tip(15)
b24 = self.next_block(24, spend=out[6]) b24 = self.next_block(24, spend=out[6])
script_length = MAX_BLOCK_BASE_SIZE - len(b24.serialize()) - 69 script_length = (MAX_BLOCK_WEIGHT - b24.get_weight() - 276) // 4
script_output = CScript([b'\x00' * (script_length + 1)]) script_output = CScript([b'\x00' * (script_length + 1)])
tx.vout = [CTxOut(0, script_output)] tx.vout = [CTxOut(0, script_output)]
b24 = self.update_block(24, [tx]) b24 = self.update_block(24, [tx])
assert_equal(len(b24.serialize()), MAX_BLOCK_BASE_SIZE + 1) assert_equal(b24.get_weight(), MAX_BLOCK_WEIGHT + 1 * 4)
self.send_blocks([b24], success=False, reject_reason='bad-blk-length', reconnect=True) self.send_blocks([b24], success=False, reject_reason='bad-blk-length', reconnect=True)
b25 = self.next_block(25, spend=out[7]) b25 = self.next_block(25, spend=out[7])
@ -484,13 +484,13 @@ class FullBlockTest(BitcoinTestFramework):
# Until block is full, add tx's with 1 satoshi to p2sh_script, the rest to OP_TRUE # Until block is full, add tx's with 1 satoshi to p2sh_script, the rest to OP_TRUE
tx_new = None tx_new = None
tx_last = tx tx_last = tx
total_size = len(b39.serialize()) total_weight = b39.get_weight()
while(total_size < MAX_BLOCK_BASE_SIZE): while total_weight < MAX_BLOCK_WEIGHT:
tx_new = self.create_tx(tx_last, 1, 1, p2sh_script) tx_new = self.create_tx(tx_last, 1, 1, p2sh_script)
tx_new.vout.append(CTxOut(tx_last.vout[1].nValue - 1, CScript([OP_TRUE]))) tx_new.vout.append(CTxOut(tx_last.vout[1].nValue - 1, CScript([OP_TRUE])))
tx_new.rehash() tx_new.rehash()
total_size += len(tx_new.serialize()) total_weight += tx_new.get_weight()
if total_size >= MAX_BLOCK_BASE_SIZE: if total_weight >= MAX_BLOCK_WEIGHT:
break break
b39.vtx.append(tx_new) # add tx to block b39.vtx.append(tx_new) # add tx to block
tx_last = tx_new tx_last = tx_new
@ -501,7 +501,7 @@ class FullBlockTest(BitcoinTestFramework):
# Make sure we didn't accidentally make too big a block. Note that the # Make sure we didn't accidentally make too big a block. Note that the
# size of the block has non-determinism due to the ECDSA signature in # size of the block has non-determinism due to the ECDSA signature in
# the first transaction. # the first transaction.
while (len(b39.serialize()) >= MAX_BLOCK_BASE_SIZE): while b39.get_weight() >= MAX_BLOCK_WEIGHT:
del b39.vtx[-1] del b39.vtx[-1]
b39 = self.update_block(39, []) b39 = self.update_block(39, [])
@ -891,7 +891,7 @@ class FullBlockTest(BitcoinTestFramework):
self.send_blocks([b63], success=False, reject_reason='bad-txns-nonfinal', reconnect=True) self.send_blocks([b63], success=False, reject_reason='bad-txns-nonfinal', reconnect=True)
# This checks that a block with a bloated VARINT between the block_header and the array of tx such that # This checks that a block with a bloated VARINT between the block_header and the array of tx such that
# the block is > MAX_BLOCK_BASE_SIZE with the bloated varint, but <= MAX_BLOCK_BASE_SIZE without the bloated varint, # the block is > MAX_BLOCK_WEIGHT with the bloated varint, but <= MAX_BLOCK_WEIGHT without the bloated varint,
# does not cause a subsequent, identical block with canonical encoding to be rejected. The test does not # does not cause a subsequent, identical block with canonical encoding to be rejected. The test does not
# care whether the bloated block is accepted or rejected; it only cares that the second block is accepted. # care whether the bloated block is accepted or rejected; it only cares that the second block is accepted.
# #
@ -916,12 +916,12 @@ class FullBlockTest(BitcoinTestFramework):
tx = CTransaction() tx = CTransaction()
# use canonical serialization to calculate size # use canonical serialization to calculate size
script_length = MAX_BLOCK_BASE_SIZE - len(b64a.normal_serialize()) - 69 script_length = (MAX_BLOCK_WEIGHT - 4 * len(b64a.normal_serialize()) - 276) // 4
script_output = CScript([b'\x00' * script_length]) script_output = CScript([b'\x00' * script_length])
tx.vout.append(CTxOut(0, script_output)) tx.vout.append(CTxOut(0, script_output))
tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0))) tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0)))
b64a = self.update_block("64a", [tx]) b64a = self.update_block("64a", [tx])
assert_equal(len(b64a.serialize()), MAX_BLOCK_BASE_SIZE + 8) assert_equal(b64a.get_weight(), MAX_BLOCK_WEIGHT + 8 * 4)
self.send_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize()') self.send_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize()')
# bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently # bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently
@ -935,7 +935,7 @@ class FullBlockTest(BitcoinTestFramework):
b64 = CBlock(b64a) b64 = CBlock(b64a)
b64.vtx = copy.deepcopy(b64a.vtx) b64.vtx = copy.deepcopy(b64a.vtx)
assert_equal(b64.hash, b64a.hash) assert_equal(b64.hash, b64a.hash)
assert_equal(len(b64.serialize()), MAX_BLOCK_BASE_SIZE) assert_equal(b64.get_weight(), MAX_BLOCK_WEIGHT)
self.blocks[64] = b64 self.blocks[64] = b64
b64 = self.update_block(64, []) b64 = self.update_block(64, [])
self.send_blocks([b64], True) self.send_blocks([b64], True)
@ -1269,12 +1269,12 @@ class FullBlockTest(BitcoinTestFramework):
for i in range(89, LARGE_REORG_SIZE + 89): for i in range(89, LARGE_REORG_SIZE + 89):
b = self.next_block(i, spend) b = self.next_block(i, spend)
tx = CTransaction() tx = CTransaction()
script_length = MAX_BLOCK_BASE_SIZE - len(b.serialize()) - 69 script_length = (MAX_BLOCK_WEIGHT - b.get_weight() - 276) // 4
script_output = CScript([b'\x00' * script_length]) script_output = CScript([b'\x00' * script_length])
tx.vout.append(CTxOut(0, script_output)) tx.vout.append(CTxOut(0, script_output))
tx.vin.append(CTxIn(COutPoint(b.vtx[1].sha256, 0))) tx.vin.append(CTxIn(COutPoint(b.vtx[1].sha256, 0)))
b = self.update_block(i, [tx]) b = self.update_block(i, [tx])
assert_equal(len(b.serialize()), MAX_BLOCK_BASE_SIZE) assert_equal(b.get_weight(), MAX_BLOCK_WEIGHT)
blocks.append(b) blocks.append(b)
self.save_spendable_output() self.save_spendable_output()
spend = self.get_spendable_output() spend = self.get_spendable_output()

View file

@ -259,8 +259,8 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(int(self.nodes[0].getmempoolentry(txid1)["wtxid"], 16), tx1.calc_sha256(True)) assert_equal(int(self.nodes[0].getmempoolentry(txid1)["wtxid"], 16), tx1.calc_sha256(True))
# Check that weight and vsize are properly reported in mempool entry (txid1) # Check that weight and vsize are properly reported in mempool entry (txid1)
assert_equal(self.nodes[0].getmempoolentry(txid1)["vsize"], (self.nodes[0].getmempoolentry(txid1)["weight"] + 3) // 4) assert_equal(self.nodes[0].getmempoolentry(txid1)["vsize"], tx1.get_vsize())
assert_equal(self.nodes[0].getmempoolentry(txid1)["weight"], len(tx1.serialize_without_witness())*3 + len(tx1.serialize_with_witness())) assert_equal(self.nodes[0].getmempoolentry(txid1)["weight"], tx1.get_weight())
# Now create tx2, which will spend from txid1. # Now create tx2, which will spend from txid1.
tx = CTransaction() tx = CTransaction()
@ -275,8 +275,8 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(int(self.nodes[0].getmempoolentry(txid2)["wtxid"], 16), tx.calc_sha256(True)) assert_equal(int(self.nodes[0].getmempoolentry(txid2)["wtxid"], 16), tx.calc_sha256(True))
# Check that weight and vsize are properly reported in mempool entry (txid2) # Check that weight and vsize are properly reported in mempool entry (txid2)
assert_equal(self.nodes[0].getmempoolentry(txid2)["vsize"], (self.nodes[0].getmempoolentry(txid2)["weight"] + 3) // 4) assert_equal(self.nodes[0].getmempoolentry(txid2)["vsize"], tx.get_vsize())
assert_equal(self.nodes[0].getmempoolentry(txid2)["weight"], len(tx.serialize_without_witness())*3 + len(tx.serialize_with_witness())) assert_equal(self.nodes[0].getmempoolentry(txid2)["weight"], tx.get_weight())
# Now create tx3, which will spend from txid2 # Now create tx3, which will spend from txid2
tx = CTransaction() tx = CTransaction()
@ -298,8 +298,8 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(int(self.nodes[0].getmempoolentry(txid3)["wtxid"], 16), tx.calc_sha256(True)) assert_equal(int(self.nodes[0].getmempoolentry(txid3)["wtxid"], 16), tx.calc_sha256(True))
# Check that weight and vsize are properly reported in mempool entry (txid3) # Check that weight and vsize are properly reported in mempool entry (txid3)
assert_equal(self.nodes[0].getmempoolentry(txid3)["vsize"], (self.nodes[0].getmempoolentry(txid3)["weight"] + 3) // 4) assert_equal(self.nodes[0].getmempoolentry(txid3)["vsize"], tx.get_vsize())
assert_equal(self.nodes[0].getmempoolentry(txid3)["weight"], len(tx.serialize_without_witness())*3 + len(tx.serialize_with_witness())) assert_equal(self.nodes[0].getmempoolentry(txid3)["weight"], tx.get_weight())
# Mine a block to clear the gbt cache again. # Mine a block to clear the gbt cache again.
self.nodes[0].generate(1) self.nodes[0].generate(1)

View file

@ -15,7 +15,7 @@ from test_framework.messages import (
COutPoint, COutPoint,
CTxIn, CTxIn,
CTxOut, CTxOut,
MAX_BLOCK_BASE_SIZE, MAX_BLOCK_WEIGHT,
MAX_MONEY, MAX_MONEY,
tx_from_hex, tx_from_hex,
) )
@ -209,7 +209,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
self.log.info('A really large transaction') self.log.info('A really large transaction')
tx = tx_from_hex(raw_tx_reference) tx = tx_from_hex(raw_tx_reference)
tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_BASE_SIZE / len(tx.vin[0].serialize())) tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_WEIGHT // 4 / len(tx.vin[0].serialize()))
self.check_mempool_result( self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-oversize'}], result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-oversize'}],
rawtxs=[tx.serialize().hex()], rawtxs=[tx.serialize().hex()],

View file

@ -6,7 +6,7 @@
import time import time
from test_framework.messages import COIN, MAX_BLOCK_BASE_SIZE from test_framework.messages import COIN, MAX_BLOCK_WEIGHT
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error, create_confirmed_utxos, create_lots_of_big_transactions, gen_return_txouts from test_framework.util import assert_equal, assert_raises_rpc_error, create_confirmed_utxos, create_lots_of_big_transactions, gen_return_txouts
@ -61,15 +61,15 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[start_range:end_range], end_range - start_range, (i+1)*base_fee) txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[start_range:end_range], end_range - start_range, (i+1)*base_fee)
# Make sure that the size of each group of transactions exceeds # Make sure that the size of each group of transactions exceeds
# MAX_BLOCK_BASE_SIZE -- otherwise the test needs to be revised to create # MAX_BLOCK_WEIGHT // 4 -- otherwise the test needs to be revised to
# more transactions. # create more transactions.
mempool = self.nodes[0].getrawmempool(True) mempool = self.nodes[0].getrawmempool(True)
sizes = [0, 0, 0] sizes = [0, 0, 0]
for i in range(3): for i in range(3):
for j in txids[i]: for j in txids[i]:
assert j in mempool assert j in mempool
sizes[i] += mempool[j]['vsize'] sizes[i] += mempool[j]['vsize']
assert sizes[i] > MAX_BLOCK_BASE_SIZE # Fail => raise utxo_count assert sizes[i] > MAX_BLOCK_WEIGHT // 4 # Fail => raise utxo_count
# add a fee delta to something in the cheapest bucket and make sure it gets mined # add a fee delta to something in the cheapest bucket and make sure it gets mined
# also check that a different entry in the cheapest bucket is NOT mined # also check that a different entry in the cheapest bucket is NOT mined

View file

@ -4,7 +4,6 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test segwit transactions and blocks on P2P network.""" """Test segwit transactions and blocks on P2P network."""
from decimal import Decimal from decimal import Decimal
import math
import random import random
import struct import struct
import time import time
@ -21,7 +20,7 @@ from test_framework.messages import (
CTxInWitness, CTxInWitness,
CTxOut, CTxOut,
CTxWitness, CTxWitness,
MAX_BLOCK_BASE_SIZE, MAX_BLOCK_WEIGHT,
MSG_BLOCK, MSG_BLOCK,
MSG_TX, MSG_TX,
MSG_WITNESS_FLAG, MSG_WITNESS_FLAG,
@ -106,16 +105,6 @@ def sign_p2pk_witness_input(script, tx_to, in_idx, hashtype, value, key):
tx_to.wit.vtxinwit[in_idx].scriptWitness.stack = [signature, script] tx_to.wit.vtxinwit[in_idx].scriptWitness.stack = [signature, script]
tx_to.rehash() tx_to.rehash()
def get_virtual_size(witness_block):
"""Calculate the virtual size of a witness block.
Virtual size is base + witness/4."""
base_size = len(witness_block.serialize(with_witness=False))
total_size = len(witness_block.serialize())
# the "+3" is so we round up
vsize = int((3 * base_size + total_size + 3) / 4)
return vsize
def test_transaction_acceptance(node, p2p, tx, with_witness, accepted, reason=None): def test_transaction_acceptance(node, p2p, tx, with_witness, accepted, reason=None):
"""Send a transaction to the node and check that it's accepted to the mempool """Send a transaction to the node and check that it's accepted to the mempool
@ -437,8 +426,7 @@ class SegWitTest(BitcoinTestFramework):
rpc_details = self.nodes[0].getblock(block.hash, True) rpc_details = self.nodes[0].getblock(block.hash, True)
assert_equal(rpc_details["size"], len(block.serialize())) assert_equal(rpc_details["size"], len(block.serialize()))
assert_equal(rpc_details["strippedsize"], len(block.serialize(False))) assert_equal(rpc_details["strippedsize"], len(block.serialize(False)))
weight = 3 * len(block.serialize(False)) + len(block.serialize()) assert_equal(rpc_details["weight"], block.get_weight())
assert_equal(rpc_details["weight"], weight)
# Upgraded node should not ask for blocks from unupgraded # Upgraded node should not ask for blocks from unupgraded
block4 = self.build_next_block(version=4) block4 = self.build_next_block(version=4)
@ -849,7 +837,7 @@ class SegWitTest(BitcoinTestFramework):
block.solve() block.solve()
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.append(b'a' * 5000000) block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.append(b'a' * 5000000)
assert get_virtual_size(block) > MAX_BLOCK_BASE_SIZE assert block.get_weight() > MAX_BLOCK_WEIGHT
# We can't send over the p2p network, because this is too big to relay # We can't send over the p2p network, because this is too big to relay
# TODO: repeat this test with a block that can be relayed # TODO: repeat this test with a block that can be relayed
@ -858,7 +846,7 @@ class SegWitTest(BitcoinTestFramework):
assert self.nodes[0].getbestblockhash() != block.hash assert self.nodes[0].getbestblockhash() != block.hash
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.pop() block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.pop()
assert get_virtual_size(block) < MAX_BLOCK_BASE_SIZE assert block.get_weight() < MAX_BLOCK_WEIGHT
assert_equal(None, self.nodes[0].submitblock(block.serialize().hex())) assert_equal(None, self.nodes[0].submitblock(block.serialize().hex()))
assert self.nodes[0].getbestblockhash() == block.hash assert self.nodes[0].getbestblockhash() == block.hash
@ -920,11 +908,10 @@ class SegWitTest(BitcoinTestFramework):
child_tx.rehash() child_tx.rehash()
self.update_witness_block_with_transactions(block, [parent_tx, child_tx]) self.update_witness_block_with_transactions(block, [parent_tx, child_tx])
vsize = get_virtual_size(block) additional_bytes = MAX_BLOCK_WEIGHT - block.get_weight()
additional_bytes = (MAX_BLOCK_BASE_SIZE - vsize) * 4
i = 0 i = 0
while additional_bytes > 0: while additional_bytes > 0:
# Add some more bytes to each input until we hit MAX_BLOCK_BASE_SIZE+1 # Add some more bytes to each input until we hit MAX_BLOCK_WEIGHT+1
extra_bytes = min(additional_bytes + 1, 55) extra_bytes = min(additional_bytes + 1, 55)
block.vtx[-1].wit.vtxinwit[int(i / (2 * NUM_DROPS))].scriptWitness.stack[i % (2 * NUM_DROPS)] = b'a' * (195 + extra_bytes) block.vtx[-1].wit.vtxinwit[int(i / (2 * NUM_DROPS))].scriptWitness.stack[i % (2 * NUM_DROPS)] = b'a' * (195 + extra_bytes)
additional_bytes -= extra_bytes additional_bytes -= extra_bytes
@ -933,8 +920,7 @@ class SegWitTest(BitcoinTestFramework):
block.vtx[0].vout.pop() # Remove old commitment block.vtx[0].vout.pop() # Remove old commitment
add_witness_commitment(block) add_witness_commitment(block)
block.solve() block.solve()
vsize = get_virtual_size(block) assert_equal(block.get_weight(), MAX_BLOCK_WEIGHT + 1)
assert_equal(vsize, MAX_BLOCK_BASE_SIZE + 1)
# Make sure that our test case would exceed the old max-network-message # Make sure that our test case would exceed the old max-network-message
# limit # limit
assert len(block.serialize()) > 2 * 1024 * 1024 assert len(block.serialize()) > 2 * 1024 * 1024
@ -947,7 +933,7 @@ class SegWitTest(BitcoinTestFramework):
block.vtx[0].vout.pop() block.vtx[0].vout.pop()
add_witness_commitment(block) add_witness_commitment(block)
block.solve() block.solve()
assert get_virtual_size(block) == MAX_BLOCK_BASE_SIZE assert block.get_weight() == MAX_BLOCK_WEIGHT
test_witness_block(self.nodes[0], self.test_node, block, accepted=True) test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
@ -1304,10 +1290,9 @@ class SegWitTest(BitcoinTestFramework):
raw_tx = self.nodes[0].getrawtransaction(tx3.hash, 1) raw_tx = self.nodes[0].getrawtransaction(tx3.hash, 1)
assert_equal(int(raw_tx["hash"], 16), tx3.calc_sha256(True)) assert_equal(int(raw_tx["hash"], 16), tx3.calc_sha256(True))
assert_equal(raw_tx["size"], len(tx3.serialize_with_witness())) assert_equal(raw_tx["size"], len(tx3.serialize_with_witness()))
weight = len(tx3.serialize_with_witness()) + 3 * len(tx3.serialize_without_witness()) vsize = tx3.get_vsize()
vsize = math.ceil(weight / 4)
assert_equal(raw_tx["vsize"], vsize) assert_equal(raw_tx["vsize"], vsize)
assert_equal(raw_tx["weight"], weight) assert_equal(raw_tx["weight"], tx3.get_weight())
assert_equal(len(raw_tx["vin"][0]["txinwitness"]), 1) assert_equal(len(raw_tx["vin"][0]["txinwitness"]), 1)
assert_equal(raw_tx["vin"][0]["txinwitness"][0], witness_script.hex()) assert_equal(raw_tx["vin"][0]["txinwitness"][0], witness_script.hex())
assert vsize != raw_tx["size"] assert vsize != raw_tx["size"]
@ -1663,7 +1648,7 @@ class SegWitTest(BitcoinTestFramework):
block.vtx.append(tx) block.vtx.append(tx)
# Test the block periodically, if we're close to maxblocksize # Test the block periodically, if we're close to maxblocksize
if (get_virtual_size(block) > MAX_BLOCK_BASE_SIZE - 1000): if block.get_weight() > MAX_BLOCK_WEIGHT - 4000:
self.update_witness_block_with_transactions(block, []) self.update_witness_block_with_transactions(block, [])
test_witness_block(self.nodes[0], self.test_node, block, accepted=True) test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
block = self.build_next_block() block = self.build_next_block()

View file

@ -33,7 +33,7 @@ from test_framework.siphash import siphash256
from test_framework.util import assert_equal from test_framework.util import assert_equal
MAX_LOCATOR_SZ = 101 MAX_LOCATOR_SZ = 101
MAX_BLOCK_BASE_SIZE = 1000000 MAX_BLOCK_WEIGHT = 4000000
MAX_BLOOM_FILTER_SIZE = 36000 MAX_BLOOM_FILTER_SIZE = 36000
MAX_BLOOM_HASH_FUNCS = 50 MAX_BLOOM_HASH_FUNCS = 50
@ -608,12 +608,15 @@ class CTransaction:
return False return False
return True return True
# Calculate the virtual transaction size using witness and non-witness # Calculate the transaction weight using witness and non-witness
# serialization size (does NOT use sigops). # serialization size (does NOT use sigops).
def get_vsize(self): def get_weight(self):
with_witness_size = len(self.serialize_with_witness()) with_witness_size = len(self.serialize_with_witness())
without_witness_size = len(self.serialize_without_witness()) without_witness_size = len(self.serialize_without_witness())
return math.ceil(((WITNESS_SCALE_FACTOR - 1) * without_witness_size + with_witness_size) / WITNESS_SCALE_FACTOR) return (WITNESS_SCALE_FACTOR - 1) * without_witness_size + with_witness_size
def get_vsize(self):
return math.ceil(self.get_weight() / WITNESS_SCALE_FACTOR)
def __repr__(self): def __repr__(self):
return "CTransaction(nVersion=%i vin=%s vout=%s wit=%s nLockTime=%i)" \ return "CTransaction(nVersion=%i vin=%s vout=%s wit=%s nLockTime=%i)" \
@ -761,6 +764,13 @@ class CBlock(CBlockHeader):
self.nNonce += 1 self.nNonce += 1
self.rehash() self.rehash()
# Calculate the block weight using witness and non-witness
# serialization size (does NOT use sigops).
def get_weight(self):
with_witness_size = len(self.serialize(with_witness=True))
without_witness_size = len(self.serialize(with_witness=False))
return (WITNESS_SCALE_FACTOR - 1) * without_witness_size + with_witness_size
def __repr__(self): def __repr__(self):
return "CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x vtx=%s)" \ return "CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x vtx=%s)" \
% (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot, % (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot,