def test_construct_block_for_mining_with_non_coinbase_transactions(): coinstate = _read_chain_from_disk(5) transactions = [ Transaction( inputs=[ Input( OutputReference( coinstate.at_head.block_by_height[0].transactions[0]. hash(), 0), SECP256k1Signature(b'y' * 64), ) ], outputs=[Output(9 * SASHIMI_PER_COIN, example_public_key)], ) ] block = construct_block_for_mining(coinstate, transactions, example_public_key, 1231006505, b'skepticoin is digital bitcoin', 1234) assert 6 == block.height assert 2 == len(block.transactions) assert 11 * SASHIMI_PER_COIN == block.transactions[0].outputs[ 0].value # 10 mined + 1 fee assert example_public_key == block.transactions[0].outputs[0].public_key assert 1231006505 == block.timestamp assert b'skepticoin is digital bitcoin' == block.transactions[0].inputs[ 0].signature.signature assert 1234 == block.nonce
def test_uto_apply_transaction_on_non_coinbase_transaction(): public_key = SECP256k1PublicKey(b'x' * 64) output_0 = Output(40, public_key) output_1 = Output(34, public_key) output_2 = Output(30, public_key) previous_transaction_hash = b'a' * 32 unspent_transaction_outs = immutables.Map({ OutputReference(previous_transaction_hash, 0): output_0, OutputReference(previous_transaction_hash, 1): output_1, }) transaction = Transaction(inputs=[ Input( OutputReference(previous_transaction_hash, 1), SECP256k1Signature(b'y' * 64), ) ], outputs=[output_2]) result = uto_apply_transaction(unspent_transaction_outs, transaction, is_coinbase=False) assert OutputReference(previous_transaction_hash, 0) in result assert OutputReference(previous_transaction_hash, 1) not in result # spent assert OutputReference(transaction.hash(), 0) in result assert result[OutputReference(previous_transaction_hash, 0)] == output_0 assert result[OutputReference(transaction.hash(), 0)] == output_2
def test_pkb_apply_transaction_on_non_coinbase_transaction(): public_key_0 = SECP256k1PublicKey(b'\x00' * 64) public_key_1 = SECP256k1PublicKey(b'\x01' * 64) public_key_2 = SECP256k1PublicKey(b'\x02' * 64) output_0 = Output(40, public_key_0) output_1 = Output(34, public_key_1) output_3 = Output(66, public_key_1) final_output = Output(30, public_key_2) previous_transaction_hash = b'a' * 32 unspent_transaction_outs = immutables.Map({ OutputReference(previous_transaction_hash, 0): output_0, OutputReference(previous_transaction_hash, 1): output_1, OutputReference(previous_transaction_hash, 2): output_3, }) public_key_balances = immutables.Map({ public_key_0: PKBalance(0, []), public_key_1: PKBalance(100, [ OutputReference(previous_transaction_hash, 1), OutputReference(previous_transaction_hash, 2), ]), }) transaction = Transaction(inputs=[ Input( OutputReference(previous_transaction_hash, 1), SECP256k1Signature(b'y' * 64), ) ], outputs=[final_output]) result = pkb_apply_transaction(unspent_transaction_outs, public_key_balances, transaction, is_coinbase=False) assert result[ public_key_0].value == 0 # not referenced in the transaction under consideration assert result[public_key_0].output_references == [] assert result[public_key_1].value == 100 - 34 assert result[public_key_1].output_references == [ OutputReference(previous_transaction_hash, 2) ] assert result[ public_key_2].value == 30 # the value of the transaction output assert result[public_key_2].output_references == [ OutputReference(transaction.hash(), 0) ]
def test_transaction_serialization(): trans = Transaction( inputs=[ Input(output_reference=OutputReference(b"b" * 32, 1234), signature=SECP256k1Signature(b"b" * 64)) ], outputs=[Output(value=1582, public_key=SECP256k1PublicKey(b"g" * 64))], ) serialize_and_deserialize(trans)
def test_validate_non_coinbase_transaction_by_itself_max_size(): transaction = Transaction(inputs=[ Input( OutputReference(b'a' * 32, 1), SECP256k1Signature(b'y' * 64), ) ] * 30_000, outputs=[Output(30, example_public_key)]) with pytest.raises(ValidateTransactionError, match=".*MAX_BLOCK_SIZE.*"): validate_non_coinbase_transaction_by_itself(transaction)
def test_transaction_repr(): trans = Transaction( inputs=[ Input(output_reference=OutputReference(b"b" * 32, 1234), signature=SECP256k1Signature(b"b" * 64)) ], outputs=[Output(value=1582, public_key=SECP256k1PublicKey(b"g" * 64))], ) assert repr( trans ) == "Transaction #4025f3f13790dc96d857562dabcdd257ee9dfd95ce126e11d8cbbe64ac1bbec4"
def test_validate_non_coinbase_transaction_by_itself_is_not_coinbase(): transaction = Transaction(inputs=[ Input( OutputReference(b'\x00' * 32, 0), SECP256k1Signature(b'y' * 64), ) ], outputs=[Output(30, example_public_key)]) with pytest.raises(ValidateTransactionError, match=".*null-reference in non-coinbase transaction.*"): validate_non_coinbase_transaction_by_itself(transaction)
def test_validate_non_coinbase_transaction_by_itself_max_total_output(): transaction = Transaction( inputs=[ Input( OutputReference(b'a' * 32, 1), SECP256k1Signature(b'y' * 64), ) ], outputs=[Output(21_000_000 * SASHIMI_PER_COIN, example_public_key)]) with pytest.raises(ValidationError, match=".out of range.*"): validate_non_coinbase_transaction_by_itself(transaction)
def test_validate_non_coinbase_transaction_by_itself_no_outputs(): transaction = Transaction( inputs=[ Input( OutputReference(b'a' * 32, 1), SECP256k1Signature(b'y' * 64), ) ], outputs=[], ) with pytest.raises(ValidateTransactionError, match=".*No outputs.*"): validate_non_coinbase_transaction_by_itself(transaction)
def test_validate_non_coinbase_transaction_by_itself_no_duplicate_output_references( ): transaction = Transaction(inputs=[ Input( OutputReference(b'a' * 32, 1), SECP256k1Signature(b'y' * 64), ) ] * 2, outputs=[Output(30, example_public_key)]) with pytest.raises(ValidateTransactionError, match=".*output_reference referenced more than once.*"): validate_non_coinbase_transaction_by_itself(transaction)
def test_get_transaction_fee(): public_key = SECP256k1PublicKey(b'x' * 64) previous_transaction_hash = b'a' * 32 unspent_transaction_outs = immutables.Map({ OutputReference(previous_transaction_hash, 0): Output(40, public_key), OutputReference(previous_transaction_hash, 1): Output(34, public_key), }) transaction = Transaction( inputs=[Input( OutputReference(previous_transaction_hash, 1), SECP256k1Signature(b'y' * 64), )], outputs=[Output(30, public_key)] ) assert get_transaction_fee(transaction, unspent_transaction_outs) == 34 - 30 # 4
def test_validate_block_by_itself_invalid_coinbase_transaction(): coinstate = CoinState.empty() transactions = [ Transaction(inputs=[ Input( OutputReference(b'x' * 32, 1), SECP256k1Signature(b'y' * 64), ) ], outputs=[Output(1, example_public_key)]) ] summary = construct_minable_summary(coinstate, transactions, 1615209942, 39) evidence = construct_pow_evidence(coinstate, summary, 0, transactions) block = Block(BlockHeader(summary, evidence), transactions) with pytest.raises(ValidateTransactionError, match=".*thin air.*"): validate_block_by_itself(block, 1615209942)
def test_validate_block_by_itself_max_block_size(mocker): # work around get_block_fees... because we would need a coinstate w/ 50_000 unspent outputs to make it work. mocker.patch("skepticoin.consensus.get_block_fees", return_value=0) transactions = [ Transaction(inputs=[ Input( OutputReference(i.to_bytes(32, 'big'), 1), SECP256k1Signature(b'y' * 64), ) ], outputs=[Output(1, example_public_key)]) for i in range(50_000) ] block = construct_block_for_mining_genesis(transactions, example_public_key, 1231006505, b'', 22) with pytest.raises(ValidateBlockError, match=".*MAX_BLOCK_SIZE.*"): validate_block_by_itself(block, 1615209942)
def test_block_serialization(): block = Block( header=BlockHeader( summary=example_block_summary, pow_evidence=example_pow_evidence, ), transactions=[ Transaction( inputs=[ Input(output_reference=OutputReference(b"b" * 32, 1234), signature=SECP256k1Signature(b"b" * 64)) ], outputs=[ Output(value=1582, public_key=SECP256k1PublicKey(b"g" * 64)) ], ) ] * 2, ) serialize_and_deserialize(block)
def test_validate_coinbase_transaction_by_itself_should_have_coinbasedata(): cb = _get_example_coinbase_transaction() cb.inputs[0].signature = SECP256k1Signature(b'c' * 64) with pytest.raises(ValidateTransactionError, match=".*CoinbaseData.*"): validate_coinbase_transaction_by_itself(cb)
def test_signature_serialization(): sig = SECP256k1Signature(b"a" * 64) serialize_and_deserialize(sig, Signature)
def test_input_serialization(): inp = Input( output_reference=OutputReference(b"b" * 32, 1234), signature=SECP256k1Signature(b"b" * 64), ) serialize_and_deserialize(inp)