Changeset View
Changeset View
Standalone View
Standalone View
test/functional/p2p-fullblocktest.py
Show First 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True): | ||||
coinbase.vout[0].nValue += spend.tx.vout[spend.n].nValue - 1 | coinbase.vout[0].nValue += spend.tx.vout[spend.n].nValue - 1 | ||||
assert(coinbase.vout[0].nValue) | assert(coinbase.vout[0].nValue) | ||||
coinbase.rehash() | coinbase.rehash() | ||||
block = create_block(base_block_hash, coinbase, block_time) | block = create_block(base_block_hash, coinbase, block_time) | ||||
# spend 1 satoshi | # spend 1 satoshi | ||||
tx = create_transaction(spend.tx, spend.n, b"", 1, script) | tx = create_transaction(spend.tx, spend.n, b"", 1, script) | ||||
self.sign_tx(tx, spend.tx, spend.n) | self.sign_tx(tx, spend.tx, spend.n) | ||||
self.add_transactions_to_block(block, [tx]) | self.add_transactions_to_block(block, [tx]) | ||||
make_conform_to_ctor(block) | |||||
block.hashMerkleRoot = block.calc_merkle_root() | block.hashMerkleRoot = block.calc_merkle_root() | ||||
if solve: | if solve: | ||||
block.solve() | block.solve() | ||||
self.tip = block | self.tip = block | ||||
self.block_heights[block.sha256] = height | self.block_heights[block.sha256] = height | ||||
assert number not in self.blocks | assert number not in self.blocks | ||||
self.blocks[number] = block | self.blocks[number] = block | ||||
return block | return block | ||||
Show All 25 Lines | def get_tests(self): | ||||
def tip(number): | def tip(number): | ||||
self.tip = self.blocks[number] | self.tip = self.blocks[number] | ||||
# adds transactions to the block and updates state | # adds transactions to the block and updates state | ||||
def update_block(block_number, new_transactions): | def update_block(block_number, new_transactions): | ||||
block = self.blocks[block_number] | block = self.blocks[block_number] | ||||
self.add_transactions_to_block(block, new_transactions) | self.add_transactions_to_block(block, new_transactions) | ||||
old_sha256 = block.sha256 | old_sha256 = block.sha256 | ||||
make_conform_to_ctor(block) | |||||
block.hashMerkleRoot = block.calc_merkle_root() | block.hashMerkleRoot = block.calc_merkle_root() | ||||
block.solve() | block.solve() | ||||
# Update the internal state just like in next_block | # Update the internal state just like in next_block | ||||
self.tip = block | self.tip = block | ||||
if block.sha256 != old_sha256: | if block.sha256 != old_sha256: | ||||
self.block_heights[ | self.block_heights[ | ||||
block.sha256] = self.block_heights[old_sha256] | block.sha256] = self.block_heights[old_sha256] | ||||
del self.block_heights[old_sha256] | del self.block_heights[old_sha256] | ||||
▲ Show 20 Lines • Show All 363 Lines • ▼ Show 20 Lines | def get_tests(self): | ||||
# Test sigops in P2SH redeem scripts | # Test sigops in P2SH redeem scripts | ||||
# | # | ||||
# b40 creates 3333 tx's spending the 6-sigop P2SH outputs from b39 for a total of 19998 sigops. | # b40 creates 3333 tx's spending the 6-sigop P2SH outputs from b39 for a total of 19998 sigops. | ||||
# The first tx has one sigop and then at the end we add 2 more to put us just over the max. | # The first tx has one sigop and then at the end we add 2 more to put us just over the max. | ||||
# | # | ||||
# b41 does the same, less one, so it has the maximum sigops permitted. | # b41 does the same, less one, so it has the maximum sigops permitted. | ||||
# | # | ||||
tip(39) | def generate_chained_txs_with_p2sh(start_tx, numTxs): | ||||
b40 = block(40, spend=out[12]) | lastOutpoint = COutPoint(start_tx.sha256, 0) | ||||
sigops = get_legacy_sigopcount_block(b40) | lastAmount = start_tx.vout[0].nValue | ||||
numTxes = (MAX_BLOCK_SIGOPS_PER_MB - sigops) // b39_sigops_per_output | |||||
assert_equal(numTxes <= b39_outputs, True) | |||||
lastOutpoint = COutPoint(b40.vtx[1].sha256, 0) | |||||
lastAmount = b40.vtx[1].vout[0].nValue | |||||
new_txs = [] | new_txs = [] | ||||
for i in range(1, numTxes + 1): | for i in range(1, numTxs + 1): | ||||
tx = CTransaction() | tx = CTransaction() | ||||
tx.vout.append(CTxOut(1, CScript([OP_TRUE]))) | tx.vout.append(CTxOut(1, CScript([OP_TRUE]))) | ||||
tx.vin.append(CTxIn(lastOutpoint, b'')) | tx.vin.append(CTxIn(lastOutpoint, b'')) | ||||
# second input is corresponding P2SH output from b39 | # second input is corresponding P2SH output from b39 | ||||
tx.vin.append(CTxIn(COutPoint(b39.vtx[i].sha256, 0), b'')) | tx.vin.append(CTxIn(COutPoint(b39.vtx[i].sha256, 0), b'')) | ||||
# Note: must pass the redeem_script (not p2sh_script) to the | # Note: must pass the redeem_script (not p2sh_script) to the | ||||
# signature hash function | # signature hash function | ||||
sighash = SignatureHashForkId( | sighash = SignatureHashForkId( | ||||
redeem_script, tx, 1, SIGHASH_ALL | SIGHASH_FORKID, | redeem_script, tx, 1, SIGHASH_ALL | SIGHASH_FORKID, | ||||
lastAmount) | lastAmount) | ||||
sig = self.coinbase_key.sign( | sig = self.coinbase_key.sign( | ||||
sighash) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID])) | sighash) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID])) | ||||
scriptSig = CScript([sig, redeem_script]) | scriptSig = CScript([sig, redeem_script]) | ||||
tx.vin[1].scriptSig = scriptSig | tx.vin[1].scriptSig = scriptSig | ||||
pad_tx(tx) | pad_tx(tx) | ||||
tx.rehash() | tx.rehash() | ||||
new_txs.append(tx) | new_txs.append(tx) | ||||
lastOutpoint = COutPoint(tx.sha256, 0) | lastOutpoint = COutPoint(tx.sha256, 0) | ||||
lastAmount = tx.vout[0].nValue | lastAmount = tx.vout[0].nValue | ||||
return new_txs, lastOutpoint, lastAmount | |||||
tip(39) | |||||
b40 = block(40, spend=out[12]) | |||||
sigops = get_legacy_sigopcount_block(b40) | |||||
numTxs = (MAX_BLOCK_SIGOPS_PER_MB - sigops) // b39_sigops_per_output | |||||
assert_equal(numTxs <= b39_outputs, True) | |||||
new_txs, lastOutpoint, lastAmount = generate_chained_txs_with_p2sh( | |||||
b40.vtx[1], numTxs) | |||||
b40_sigops_to_fill = MAX_BLOCK_SIGOPS_PER_MB - \ | b40_sigops_to_fill = MAX_BLOCK_SIGOPS_PER_MB - \ | ||||
(numTxes * b39_sigops_per_output + sigops) + 1 | (numTxs * b39_sigops_per_output + sigops) + 1 | ||||
tx = CTransaction() | tx = CTransaction() | ||||
tx.vin.append(CTxIn(lastOutpoint, b'')) | tx.vin.append(CTxIn(lastOutpoint, b'')) | ||||
tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b40_sigops_to_fill))) | tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b40_sigops_to_fill))) | ||||
pad_tx(tx) | |||||
tx.rehash() | |||||
new_txs.append(tx) | new_txs.append(tx) | ||||
update_block(40, new_txs) | update_block(40, new_txs) | ||||
yield rejected(RejectResult(16, b'bad-blk-sigops')) | yield rejected(RejectResult(16, b'bad-blk-sigops')) | ||||
# same as b40, but one less sigop | # same as b40, but one less sigop | ||||
tip(39) | tip(39) | ||||
b41 = block(41, spend=None) | b41 = block(41, spend=out[12]) | ||||
update_block(41, b40.vtx[1:-1]) | |||||
b41_sigops_to_fill = b40_sigops_to_fill - 1 | b41_sigops_to_fill = b40_sigops_to_fill - 1 | ||||
new_txs, lastOutpoint, lastAmount = generate_chained_txs_with_p2sh( | |||||
b41.vtx[1], numTxs) | |||||
deadalnix: This changes completely what this test is doing, why ? | |||||
schancelUnsubmitted Not Done Inline ActionsNo. It does the same thing AFAICS. The old version was invalid because of LTOR changing transaction indices in the block. So, I change it to generate the same thing twice. schancel: No. It does the same thing AFAICS. The old version was invalid because of LTOR changing… | |||||
tx = CTransaction() | tx = CTransaction() | ||||
tx.vin.append(CTxIn(lastOutpoint, b'')) | tx.vin.append(CTxIn(lastOutpoint, b'')) | ||||
tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b41_sigops_to_fill))) | tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b41_sigops_to_fill))) | ||||
pad_tx(tx) | update_block(41, new_txs + [tx]) | ||||
tx.rehash() | |||||
update_block(41, [tx]) | |||||
yield accepted() | yield accepted() | ||||
# Fork off of b39 to create a constant base again | # Fork off of b39 to create a constant base again | ||||
# | # | ||||
# b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) | # b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) | ||||
# \-> b41 (12) | # \-> b41 (12) | ||||
# | # | ||||
tip(39) | tip(39) | ||||
▲ Show 20 Lines • Show All 163 Lines • ▼ Show 20 Lines | def get_tests(self): | ||||
tx1 = create_tx(tx, 0, 1) | tx1 = create_tx(tx, 0, 1) | ||||
b57 = update_block(57, [tx, tx1]) | b57 = update_block(57, [tx, tx1]) | ||||
# b56 - copy b57, add a duplicate tx | # b56 - copy b57, add a duplicate tx | ||||
tip(55) | tip(55) | ||||
b56 = copy.deepcopy(b57) | b56 = copy.deepcopy(b57) | ||||
self.blocks[56] = b56 | self.blocks[56] = b56 | ||||
assert_equal(len(b56.vtx), 3) | assert_equal(len(b56.vtx), 3) | ||||
b56 = update_block(56, [tx1]) | b56 = update_block(56, [b57.vtx[2]]) | ||||
assert_equal(b56.hash, b57.hash) | assert_equal(b56.hashMerkleRoot, b57.hashMerkleRoot) | ||||
yield rejected(RejectResult(16, b'bad-txns-duplicate')) | yield rejected(RejectResult(16, b'bad-txns-duplicate')) | ||||
# b57p2 - a good block with 6 tx'es, don't submit until end | # b57p2 - a good block with 6 tx'es, don't submit until end | ||||
tip(55) | tip(55) | ||||
b57p2 = block("57p2") | b57p2 = block("57p2") | ||||
tx = create_and_sign_tx(out[16].tx, out[16].n, 1) | tx = create_and_sign_tx(out[16].tx, out[16].n, 1) | ||||
tx1 = create_tx(tx, 0, 1) | tx1 = create_tx(tx, 0, 1) | ||||
tx2 = create_tx(tx1, 0, 1) | tx2 = create_tx(tx1, 0, 1) | ||||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | def get_tests(self): | ||||
# use canonical serialization to calculate size | # use canonical serialization to calculate size | ||||
script_length = LEGACY_MAX_BLOCK_SIZE - \ | script_length = LEGACY_MAX_BLOCK_SIZE - \ | ||||
len(b64a.normal_serialize()) - 69 | len(b64a.normal_serialize()) - 69 | ||||
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 = update_block("64a", [tx]) | b64a = update_block("64a", [tx]) | ||||
assert_equal(len(b64a.serialize()), LEGACY_MAX_BLOCK_SIZE + 8) | assert_equal(len(b64a.serialize()), LEGACY_MAX_BLOCK_SIZE + 8) | ||||
yield TestInstance([[self.tip, None]]) | yield TestInstance([[self.tip, None]]) | ||||
# comptool workaround: to make sure b64 is delivered, manually erase | # comptool workaround: to make sure b64 is delivered, manually erase | ||||
# b64a from blockstore | # b64a from blockstore | ||||
self.test.block_store.erase(b64a.sha256) | self.test.block_store.erase(b64a.sha256) | ||||
tip(60) | tip(60) | ||||
b64 = CBlock(b64a) | b64 = CBlock(b64a) | ||||
Show All 13 Lines | def get_tests(self): | ||||
b65 = block(65) | b65 = block(65) | ||||
tx1 = create_and_sign_tx( | tx1 = create_and_sign_tx( | ||||
out[19].tx, out[19].n, out[19].tx.vout[0].nValue) | out[19].tx, out[19].n, out[19].tx.vout[0].nValue) | ||||
tx2 = create_and_sign_tx(tx1, 0, 0) | tx2 = create_and_sign_tx(tx1, 0, 0) | ||||
update_block(65, [tx1, tx2]) | update_block(65, [tx1, tx2]) | ||||
yield accepted() | yield accepted() | ||||
save_spendable_output() | save_spendable_output() | ||||
# Attempt to spend an output created later in the same block | |||||
# | |||||
# -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) | |||||
# \-> b66 (20) | |||||
tip(65) | |||||
b66 = block(66) | |||||
tx1 = create_and_sign_tx( | |||||
out[20].tx, out[20].n, out[20].tx.vout[0].nValue) | |||||
tx2 = create_and_sign_tx(tx1, 0, 1) | |||||
update_block(66, [tx2, tx1]) | |||||
yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) | |||||
# Attempt to double-spend a transaction created in a block | # Attempt to double-spend a transaction created in a block | ||||
# | # | ||||
# -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) | # -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) | ||||
# \-> b67 (20) | # \-> b67 (20) | ||||
# | # | ||||
# | # | ||||
tip(65) | tip(65) | ||||
b67 = block(67) | b67 = block(67) | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | def get_tests(self): | ||||
# b71 is a copy of 72, but re-adds one of its transactions. However, it has the same hash as b71. | # b71 is a copy of 72, but re-adds one of its transactions. However, it has the same hash as b71. | ||||
# | # | ||||
tip(69) | tip(69) | ||||
b72 = block(72) | b72 = block(72) | ||||
tx1 = create_and_sign_tx(out[21].tx, out[21].n, 2) | tx1 = create_and_sign_tx(out[21].tx, out[21].n, 2) | ||||
tx2 = create_and_sign_tx(tx1, 0, 1) | tx2 = create_and_sign_tx(tx1, 0, 1) | ||||
b72 = update_block(72, [tx1, tx2]) # now tip is 72 | b72 = update_block(72, [tx1, tx2]) # now tip is 72 | ||||
b71 = copy.deepcopy(b72) | b71 = copy.deepcopy(b72) | ||||
b71.vtx.append(tx2) # add duplicate tx2 | b71.vtx.append(b72.vtx[-1]) # add duplicate last transaction | ||||
self.block_heights[b71.sha256] = self.block_heights[ | # b71 builds off b69 | ||||
b69.sha256] + 1 # b71 builds off b69 | self.block_heights[b71.sha256] = self.block_heights[b69.sha256] + 1 | ||||
self.blocks[71] = b71 | self.blocks[71] = b71 | ||||
assert_equal(len(b71.vtx), 4) | assert_equal(len(b71.vtx), 4) | ||||
assert_equal(len(b72.vtx), 3) | assert_equal(len(b72.vtx), 3) | ||||
assert_equal(b72.sha256, b71.sha256) | assert_equal(b72.sha256, b71.sha256) | ||||
tip(71) | tip(71) | ||||
yield rejected(RejectResult(16, b'bad-txns-duplicate')) | yield rejected(RejectResult(16, b'bad-txns-duplicate')) | ||||
▲ Show 20 Lines • Show All 252 Lines • ▼ Show 20 Lines | |||||
block("alt" + str(chain1_tip + 1)) | block("alt" + str(chain1_tip + 1)) | ||||
yield accepted() | yield accepted() | ||||
# ... and re-org back to the first chain | # ... and re-org back to the first chain | ||||
tip(chain1_tip) | tip(chain1_tip) | ||||
block(chain1_tip + 1) | block(chain1_tip + 1) | ||||
yield rejected() | yield rejected() | ||||
block(chain1_tip + 2) | block(chain1_tip + 2) | ||||
yield rejected() | |||||
block(chain1_tip + 3) | |||||
yield accepted() | yield accepted() | ||||
chain1_tip += 2 | chain1_tip += 2 | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
FullBlockTest().main() | FullBlockTest().main() |
This changes completely what this test is doing, why ?