예제 #1
0
def test_pkb_apply_transaction_on_coinbase():
    public_key_0 = SECP256k1PublicKey(b'0' * 64)
    public_key_1 = SECP256k1PublicKey(b'1' * 64)

    output_0 = Output(40, public_key_0)
    output_1 = Output(34, public_key_1)

    unspent_transaction_outs = immutables.Map()
    public_key_balances = 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 = pkb_apply_transaction(unspent_transaction_outs,
                                   public_key_balances,
                                   transaction,
                                   is_coinbase=True)

    assert public_key_0 in result
    assert public_key_1 in result

    assert result[public_key_0].value == 40
    assert result[public_key_1].value == 34
예제 #2
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)
    ]
예제 #3
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
예제 #4
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
예제 #5
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)
예제 #6
0
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"
예제 #7
0
    def handle_request_scrypt_input_message(self, miner_id: int,
                                            data: int) -> None:
        nonce: int = data

        self.coinstate, transactions = self.network_thread.local_peer.chain_manager.get_state(
        )
        increasing_time = max(int(time()), self.coinstate.head().timestamp + 1)

        summary, current_height, transactions = \
            construct_block_pow_evidence_input(self.coinstate, transactions, SECP256k1PublicKey(self.public_key),
                                               increasing_time, b'', nonce)

        self.mining_args[miner_id] = summary, current_height, transactions
        self.send_message(miner_id, "scrypt_input", (summary, current_height))
예제 #8
0
    def __call__(self) -> None:
        self.prepare()
        self.send_message("start_balance", self.get_balance())
        self.send_message("info", "Starting mining: A repeat minter")

        try:
            public_key = self.get_key_for_mined_block()
            nonce = random.randrange(1 << 32)
            last_round_second = int(time())
            hashes = 0

            while True:
                current_second = int(time())

                if current_second > last_round_second:
                    self.send_message("hashes", (current_second, hashes))
                    last_round_second = current_second
                    hashes = 0

                self.coinstate, transactions = self.thread.local_peer.chain_manager.get_state(
                )
                increasing_time = max(current_second,
                                      self.coinstate.head().timestamp + 1)

                block = construct_block_for_mining(
                    self.coinstate, transactions,
                    SECP256k1PublicKey(public_key), increasing_time, b'',
                    nonce)

                hashes += 1
                nonce = (nonce + 1) % (1 << 32)

                if block.hash() < block.target:
                    self.handle_mined_block(block)
                    public_key = self.get_key_for_mined_block()

        except KeyboardInterrupt:
            self.send_message("info", "KeyboardInterrupt")

        finally:
            self.send_message("info", "Stopping networking thread")
            self.thread.stop()

            self.send_message("info", "Waiting for networking thread to stop")
            self.thread.join()

            self.send_message("info", "Done; waiting for Python-exit")
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
예제 #10
0
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)
예제 #11
0
    construct_pow_evidence,
    get_block_subsidy,
    get_transaction_fee,
    validate_coinbase_transaction_by_itself,
    validate_block_header_by_itself,
    validate_block_by_itself,
    # validate_non_coinbase_transaction_in_coinstate,
    ValidateBlockError,
    ValidateBlockHeaderError,
    ValidateTransactionError,
    ValidatePOWError,
)
from skepticoin.signing import SECP256k1PublicKey, SECP256k1Signature
from skepticoin.datatypes import Transaction, OutputReference, Input, Output, Block

example_public_key = SECP256k1PublicKey(b'x' * 64)


def get_example_genesis_block():
    return Block.deserialize(
        computer(
            """000000000000000000000000000000000000000000000000000000000000000000008278968af4bd613aa24a5ccd5280211b3101e3"""
            """ff62621bb11500509d1bbe2a956046240b0100000000000000000000000000000000000000000000000000000000000000000000d7"""
            """38f2c472180cb401f650b12be96ec25bfd9b4e9908c6c9089d9bf26401646f87000000000000000000000000000000000000000000"""
            """0000000000000000000000077a14cfbe21d47f367f23f9a464c765541b1b07bef9f5a95901e0bffe3a1a2f01000100000000000000"""
            """000000000000000000000000000000000000000000000000000000000001000000000001000000012a05f200027878787878787878"""
            """7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878"""
            """787878"""))


def test_construct_minable_summary_no_transactions():
예제 #12
0
def main() -> None:
    parser = DefaultArgumentParser()
    parser.add_argument("amount", help="The amount of to send", type=int)
    parser.add_argument("denomination", help="'skepticoin' or 'sashimi'", choices=['skepticoin', 'sashimi'])
    parser.add_argument("address", help="The address to send to")
    args = parser.parse_args()
    configure_logging_from_args(args)

    value = args.amount * (SASHIMI_PER_COIN if args.denomination == 'skepticoin' else 1)

    if not is_valid_address(args.address):
        print("Invalid address")
        return

    check_chain_dir()
    coinstate = read_chain_from_disk()
    wallet = open_or_init_wallet()
    thread = start_networking_peer_in_background(args, coinstate)

    try:
        # we need a fresh chain because our wallet doesn't track spending/receiving, so we need to look at the real
        # blockchain to know what we can spend.
        check_for_fresh_chain(thread)
        print("Chain up to date")

        target_address = SECP256k1PublicKey(parse_address(args.address))
        change_address = SECP256k1PublicKey(wallet.get_annotated_public_key("change"))
        save_wallet(wallet)

        transaction = create_spend_transaction(
            wallet,
            coinstate,
            value,
            0,  # we'll get to paying fees later
            target_address,
            change_address,
        )

        validate_non_coinbase_transaction_by_itself(transaction)
        assert coinstate.current_chain_hash
        validate_non_coinbase_transaction_in_coinstate(transaction, coinstate.current_chain_hash, coinstate)

        print("Broadcasting transaction on the network", transaction)
        thread.local_peer.network_manager.broadcast_transaction(transaction)

        print("Monitoring...")

        while True:
            sleep(5)

            # it's late and I'm too lazy for the efficient & correct implementation.
            coinstate = thread.local_peer.chain_manager.coinstate

            max_height = coinstate.head().height

            for i in range(10):
                block = coinstate.by_height_at_head()[max(max_height - i, 0)]
                if transaction in block.transactions:
                    print("Transaction confirmed at", block.height, "with", i, "confirmation blocks")

                    if i == 6:  # this is the magic number of confirmations according to the "literature" on the subject
                        thread.stop()
                        return

    except KeyboardInterrupt:
        print("KeyboardInterrupt")
    finally:
        print("Stopping networking thread")
        thread.stop()
        print("Waiting for networking thread to stop")
        thread.join()
        print("Done; waiting for Python-exit")
예제 #13
0
def test_output_serialization():
    out = Output(
        value=1582,
        public_key=SECP256k1PublicKey(b"g" * 64),
    )
    serialize_and_deserialize(out)
예제 #14
0
def test_publickey_serialization():
    pk = SECP256k1PublicKey(b"5" * 64)
    serialize_and_deserialize(pk, PublicKey)
예제 #15
0
def test_broadcast_transaction(caplog, mocker):
    # just testing the basics: is a broadcast transaction stored in the transaction pool on the other side?

    # By turning off transaction-validation, we can use an invalid transaction in this test.
    mocker.patch(
        "skepticoin.networking.peer.validate_non_coinbase_transaction_by_itself"
    )
    mocker.patch(
        "skepticoin.networking.peer.validate_non_coinbase_transaction_in_coinstate"
    )

    caplog.set_level(logging.INFO)

    coinstate = _read_chain_from_disk(5)

    thread_a = NetworkingThread(coinstate, 12412, FakeDiskInterface())
    thread_a.start()

    _try_to_connect('127.0.0.1', 12412)

    thread_b = NetworkingThread(coinstate, 12413, FakeDiskInterface())
    thread_b.local_peer.network_manager.disconnected_peers = load_peers_from_list(
        [('127.0.0.1', 12412, "OUTGOING")])
    thread_b.start()

    previous_hash = coinstate.at_head.block_by_height[0].transactions[0].hash()

    # Not actually a valid transaction (not signed)
    transaction = Transaction(
        inputs=[
            Input(OutputReference(previous_hash, 0), SignableEquivalent())
        ],
        outputs=[Output(10, SECP256k1PublicKey(b'x' * 64))],
    )

    try:
        # give both peers some time to find each other
        start_time = time()
        while True:
            if (len(thread_a.local_peer.network_manager.get_active_peers()) > 0
                    and
                    len(thread_b.local_peer.network_manager.get_active_peers())
                    > 0):
                break

            if time() > start_time + 5:
                print("\n".join(str(r) for r in caplog.records))
                raise Exception("Peers can't connect")

            sleep(0.01)

        # broadcast_transaction... the part that we're testing
        thread_a.local_peer.network_manager.broadcast_transaction(transaction)

        # wait until it's picked up on the other side
        start_time = time()
        while True:
            if len(thread_b.local_peer.chain_manager.transaction_pool) > 0:
                break

            if time() > start_time + 5:
                print("\n".join(str(r) for r in caplog.records))
                raise Exception("Transaction broadcast failed")

            sleep(0.01)

    finally:
        thread_a.stop()
        thread_a.join()

        thread_b.stop()
        thread_b.join()
예제 #16
0
def main():
    parser = DefaultArgumentParser()
    args = parser.parse_args()
    configure_logging_from_args(args)

    create_chain_dir()
    coinstate = read_chain_from_disk()
    wallet = open_or_init_wallet()
    initialize_peers_file()
    thread = start_networking_peer_in_background(args, coinstate)
    thread.local_peer.show_stats()

    if check_for_fresh_chain(thread):
        thread.local_peer.show_stats()

    print("Starting mining: A repeat minter")

    try:
        print("Starting main loop")

        while True:
            public_key = wallet.get_annotated_public_key(
                "reserved for potentially mined block")
            save_wallet(wallet)

            nonce = random.randrange(1 << 32)
            last_round_second = int(time())
            i = 0

            while True:
                if int(time()) > last_round_second:
                    print("Hashrate:", i)
                    last_round_second = int(time())
                    i = 0

                coinstate, transactions = thread.local_peer.chain_manager.get_state(
                )
                increasing_time = max(int(time()),
                                      coinstate.head().timestamp + 1)
                block = construct_block_for_mining(
                    coinstate, transactions, SECP256k1PublicKey(public_key),
                    increasing_time, b'', nonce)

                i += 1
                nonce = (nonce + 1) % (1 << 32)
                if block.hash() < block.target:
                    break

            coinstate = coinstate.add_block(block, int(time()))
            with open(Path('chain') / block_filename(block), 'wb') as f:
                f.write(block.serialize())
            print("FOUND", block_filename(block))
            print("Wallet balance: %s skepticoin" %
                  (wallet.get_balance(coinstate) / Decimal(SASHIMI_PER_COIN)))

            thread.local_peer.chain_manager.set_coinstate(coinstate)
            thread.local_peer.network_manager.broadcast_block(block)

    except KeyboardInterrupt:
        print("KeyboardInterrupt")
    finally:
        print("Stopping networking thread")
        thread.stop()
        print("Waiting for networking thread to stop")
        thread.join()
        print("Done; waiting for Python-exit")
예제 #17
0
def main():
    parser = DefaultArgumentParser()
    args = parser.parse_args()
    configure_logging_from_args(args)

    create_chain_dir()
    coinstate = read_chain_from_disk()
    wallet = open_or_init_wallet()
    initialize_peers_file()
    thread = start_networking_peer_in_background(args, coinstate)
    thread.local_peer.show_stats()

    if check_for_fresh_chain(thread):
        thread.local_peer.show_stats()

    if thread.local_peer.chain_manager.coinstate.head().height <= MAX_KNOWN_HASH_HEIGHT:
        print("Your blockchain is not just old, it is ancient; ABORTING")
        return

    start_time = datetime.now()
    start_balance = wallet.get_balance(coinstate) / Decimal(SASHIMI_PER_COIN)
    balance = start_balance
    print("Wallet balance: %s skepticoin" % start_balance)

    print("Starting mining: A repeat minter")

    try:
        print("Starting main loop")

        while True:
            public_key = wallet.get_annotated_public_key("reserved for potentially mined block")
            save_wallet(wallet)

            nonce = random.randrange(1 << 32)
            last_round_second = int(time())
            hashes = 0

            while True:
                if int(time()) > last_round_second:
                    now = datetime.now()
                    now_str = now.strftime("%Y-%m-%d %H:%M:%S")
                    uptime = now - start_time
                    uptime_str = str(uptime).split(".")[0]

                    mined = balance - start_balance
                    mine_speed = (float(mined) / uptime.total_seconds()) * 60 * 60

                    print(f"{now_str} | uptime: {uptime_str} | {hashes:>2} hash/sec" +
                          f" | mined: {mined:>3} SKEPTI | {mine_speed:5.2f} SKEPTI/h")
                    last_round_second = int(time())
                    hashes = 0

                coinstate, transactions = thread.local_peer.chain_manager.get_state()
                increasing_time = max(int(time()), coinstate.head().timestamp + 1)
                block = construct_block_for_mining(
                    coinstate, transactions, SECP256k1PublicKey(public_key), increasing_time, b'', nonce)

                hashes += 1
                nonce = (nonce + 1) % (1 << 32)
                if block.hash() < block.target:
                    break

            coinstate = coinstate.add_block(block, int(time()))
            with open(Path('chain') / block_filename(block), 'wb') as f:
                f.write(block.serialize())
            print("FOUND", block_filename(block))
            balance = (wallet.get_balance(coinstate) / Decimal(SASHIMI_PER_COIN))
            print("Wallet balance: %s skepticoin" % balance)

            thread.local_peer.chain_manager.set_coinstate(coinstate)
            thread.local_peer.network_manager.broadcast_block(block)

    except KeyboardInterrupt:
        print("KeyboardInterrupt")
    finally:
        print("Stopping networking thread")
        thread.stop()
        print("Waiting for networking thread to stop")
        thread.join()
        print("Done; waiting for Python-exit")