Пример #1
0
def test_uto_apply_transaction_on_coinbase():
    public_key = SECP256k1PublicKey(b'x' * 64)

    output_0 = Output(40, public_key)
    output_1 = Output(34, public_key)

    unspent_transaction_outs = immutables.Map()

    transaction = Transaction(inputs=[
        Input(
            construct_reference_to_thin_air(),
            CoinbaseData(0, b'coinbase of the first block'),
        )
    ],
                              outputs=[output_0, output_1])

    result = uto_apply_transaction(unspent_transaction_outs,
                                   transaction,
                                   is_coinbase=True)

    assert OutputReference(transaction.hash(), 0) in result
    assert OutputReference(transaction.hash(), 1) in result

    assert result[OutputReference(transaction.hash(), 0)] == output_0
    assert result[OutputReference(transaction.hash(), 1)] == output_1
Пример #2
0
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
Пример #3
0
    def add_transaction_to_pool(self, transaction: Transaction) -> bool:
        with self.lock:
            self.local_peer.logger.info(
                "%15s ChainManager.add_transaction_to_pool(%s)" %
                ("", human(transaction.hash())))

            try:
                validate_non_coinbase_transaction_by_itself(transaction)

                assert self.coinstate.current_chain_hash

                validate_non_coinbase_transaction_in_coinstate(
                    transaction, self.coinstate.current_chain_hash,
                    self.coinstate)

                # Horribly inefficiently implemented (AKA 'room for improvement)
                validate_no_duplicate_output_references_in_transactions(
                    self.transaction_pool + [transaction])

                #  we don't do validate_no_duplicate_transactions here (assuming it's just been done before
                #  add_transaction_to_pool).

            except ValidateTransactionError as e:
                # TODO: dirty hack at this particular point... to allow for e.g. out-of-order transactions to not take
                # down the whole peer, but this should more specifically match for a short list of OK problems.
                self.local_peer.logger.warning("%15s INVALID transaction %s" %
                                               ("", str(e)))
                self.local_peer.disk_interface.save_transaction_for_debugging(
                    transaction)

                return False  # not successful

            self.transaction_pool.append(transaction)

        return True  # successfully added
Пример #4
0
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)
    ]
Пример #5
0
def pkb2_apply_transaction(
    unspent_transaction_outs: immutables.Map[OutputReference, Output],
    public_key_balances: immutables.Map[PublicKey, PKBalance2],
    transaction: Transaction,
    is_coinbase: bool,
) -> immutables.Map[PublicKey, PKBalance2]:
    with public_key_balances.mutate() as mutable_public_key_balances:
        # for coinbase we must skip the input-removal because the input references "thin air" rather than an output.
        if not is_coinbase:
            for input in transaction.inputs:
                previously_unspent_output: Output = unspent_transaction_outs[
                    input.output_reference]

                public_key = previously_unspent_output.public_key
                mutable_public_key_balances[public_key] = PKBalance2(
                    value=mutable_public_key_balances[public_key].value -
                    previously_unspent_output.value,
                    all_output_references=mutable_public_key_balances[
                        public_key].all_output_references,
                    unspent_output_references=([
                        to for to in mutable_public_key_balances[public_key].
                        unspent_output_references
                        if to != input.output_reference
                    ]),

                    # in principle a single public_key could be spent more than once in a single transaction, we
                    # could change the below into a set (or alternatively, note an input index)
                    spent_in_transactions=mutable_public_key_balances[
                        public_key].spent_in_transactions + [transaction],
                )

        for i, output in enumerate(transaction.outputs):
            output_reference = OutputReference(transaction.hash(), i)

            if output.public_key not in mutable_public_key_balances:
                mutable_public_key_balances[output.public_key] = PKBalance2(
                    0, [], [], [])

            mutable_public_key_balances[output.public_key] = PKBalance2(
                value=mutable_public_key_balances[output.public_key].value +
                output.value,
                all_output_references=(mutable_public_key_balances[
                    output.public_key].all_output_references +
                                       [output_reference]),
                unspent_output_references=(mutable_public_key_balances[
                    output.public_key].unspent_output_references +
                                           [output_reference]),
                spent_in_transactions=mutable_public_key_balances[
                    output.public_key].spent_in_transactions,
            )

        return mutable_public_key_balances.finish()
Пример #6
0
 def save_transaction_for_debugging(self, transaction: Transaction) -> None:
     with open("/tmp/%s.transaction" % human(transaction.hash()),
               'wb') as f:
         f.write(transaction.serialize())