Esempio n. 1
0
 def test_block_parsing_and_serialization(self):
     tx_in = TxIn(
         prev_tx=b'\x00' * 32,
         prev_index=0xffffffff,
         script_sig=Script([b'muhhh coinz']),
     )
     sk = create_sk(100)
     sec = sk.verifying_key.to_sec(compressed=False)
     tx_out = TxOut(
         amount=50 * 100_000_000,
         script_pubkey=p2pk_script(sec),
     )
     coinbase = Tx(
         version=1,
         tx_ins=[tx_in],
         tx_outs=[tx_out],
         locktime=0,
     )
     block = mine(
         Block(version=1,
               prev_block=genesis.hash(),
               merkle_root=merkle_root([coinbase.hash()]),
               timestamp=int(time.time()),
               bits=starting_bits,
               nonce=b'\x00\x00\x00\x00',
               txns=[coinbase]))
     assert Block.parse(BytesIO(block.serialize())).hash() == block.hash()
Esempio n. 2
0
def insufficient_proof(bitcoin_node):
    block = Block(
        version=1,
        prev_block=bitcoin_node.headers[-1].hash(),
        merkle_root=merkle_root([b'xyz']),  # FIXME
        timestamp=int(time.time()),
        bits=starting_bits,
        nonce=b'\x00\x00\x00\x00',
        txns=[prepare_coinbase(bob_sec)])
    assert not block.check_pow()
    valid = False
    hints = make_hints([
        f'Proof-of-Work not satisfied',
    ])
    return block, valid, hints
Esempio n. 3
0
def spend_nonexistant_output(bitcoin_node):
    coinbase = prepare_coinbase(bob_sec)
    tx_in = TxIn(
        prev_tx=urandom(32),
        prev_index=0,
        script_sig=p2pk_script(bob_sec),
    )
    tx_out = TxOut(
        amount=50 * 100_000_000,
        script_pubkey=p2pk_script(bob_sec),
    )
    bad_spend = Tx(
        version=1,
        tx_ins=[tx_in],
        tx_outs=[tx_out],
        locktime=0,
    )
    block = mine(
        Block(
            version=1,
            prev_block=bitcoin_node.headers[-1].hash(),
            merkle_root=merkle_root([coinbase.hash(),
                                     bad_spend.hash()]),  # FIXME
            timestamp=int(time.time()),
            bits=starting_bits,
            nonce=b'\x00\x00\x00\x00',
            txns=[coinbase, bad_spend],
        ))
    valid = False
    hints = make_hints([
        'this transaction spends an output that does not exist',
    ])
    # FIXME: check that utxo_set was updated
    return block, valid, hints
Esempio n. 4
0
def bad_coinbase(bitcoin_node):
    # this scenario sucks b/c we test multiple things and it's unclear whether the latter
    # checks are even happening
    tx_in = TxIn(
        prev_tx=b'\x00' * 32,
        prev_index=0xffffffff,
        script_sig=p2pk_script(urandom(10)),
    )
    tx_out = TxOut(
        amount=100 * 100_000_000,
        script_pubkey=p2pk_script(bob_sec),
    )
    coinbase = Tx(
        version=1,
        tx_ins=[tx_in],
        tx_outs=[tx_out],
        locktime=0,
    )
    block = mine(
        Block(
            version=1,
            prev_block=bitcoin_node.headers[-1].hash(),
            merkle_root=merkle_root([coinbase.hash()]),  # FIXME
            timestamp=int(time.time()),
            bits=starting_bits,
            nonce=b'\x00\x00\x00\x00',
            txns=[coinbase]))
    valid = False
    hints = make_hints([
        "Bad coinbase",
    ])
    return block, valid, hints
Esempio n. 5
0
def wrong_bits(bitcoin_node):
    block = mine(
        Block(version=1,
              prev_block=bitcoin_node.headers[-1].hash(),
              merkle_root=merkle_root([b'xyz']),
              timestamp=int(time.time()),
              bits=target_to_bits(16**63),
              nonce=b'\x00\x00\x00\x00',
              txns=[prepare_coinbase(bob_sec)]))
    valid = False
    hints = make_hints([
        f'Block.bits should be {repr(starting_bits)}',
    ])
    return block, valid, hints
Esempio n. 6
0
def missing_coinbase(bitcoin_node):
    block = mine(
        Block(
            version=1,
            prev_block=bitcoin_node.headers[-1].hash(),
            merkle_root=merkle_root([b'xyz']),  # FIXME
            timestamp=int(time.time()),
            bits=starting_bits,
            nonce=b'\x00\x00\x00\x00',
            txns=[]))
    valid = False
    hints = make_hints([
        "Look block.txns",
        "Coinbase is missing",
    ])
    return block, valid, hints
Esempio n. 7
0
def good_coinbase(bitcoin_node):
    coinbase = prepare_coinbase(bob_sec)
    block = mine(
        Block(
            version=1,
            prev_block=bitcoin_node.headers[-1].hash(),
            merkle_root=merkle_root([coinbase.hash()]),  # FIXME
            timestamp=int(time.time()),
            bits=starting_bits,
            nonce=b'\x00\x00\x00\x00',
            txns=[coinbase]))
    valid = True
    hints = make_hints([
        'We need to update the utxo set',
    ])
    # FIXME: check that utxo_set was updated
    return block, valid, hints
Esempio n. 8
0
def first_valid_spend(bitcoin_node):
    coinbase = prepare_coinbase(bob_sec)
    assert len(list(bitcoin_node.utxo_set.keys())) == 1
    outpoint = list(bitcoin_node.utxo_set.keys())[0]  # FIXME
    utxo = bitcoin_node.utxo_set[outpoint]

    tx_in = TxIn(
        prev_tx=bytes.fromhex(outpoint[0]),
        prev_index=outpoint[1],
    )
    tx_out = TxOut(
        amount=utxo.amount - 10,
        script_pubkey=p2pk_script(bob_sec),
    )
    bad_spend = Tx(
        version=1,
        tx_ins=[tx_in],
        tx_outs=[tx_out],
        locktime=0,
    )

    ### HACKS!!! ###
    for i in range(len(bad_spend.tx_ins)):
        bad_spend.sign_input(i, bob_sk, utxo.script_pubkey)
    ### /HACKS!!! ###

    block = mine(
        Block(
            version=1,
            prev_block=bitcoin_node.headers[-1].hash(),
            merkle_root=merkle_root([coinbase.hash(),
                                     bad_spend.hash()]),  # FIXME
            timestamp=int(time.time()),
            bits=starting_bits,
            nonce=b'\x00\x00\x00\x00',
            txns=[coinbase, bad_spend],
        ))
    valid = True
    hints = make_hints([
        'did utxo set update?',
    ])
    # FIXME: check that utxo_set was updated
    return block, valid, hints
Esempio n. 9
0
 def parse(cls, stream):
     block = Block.parse(stream)
     return cls(block)
Esempio n. 10
0
 def parse(cls, stream):
     return Block.parse(stream)
Esempio n. 11
0
from io import BytesIO

from solutions.network import PeerConnection, GetHeadersMessage, HeadersMessage, GetDataMessage, BlockMessage
from solutions.block import RAW_GENESIS_BLOCK, BlockHeader, Block
from lib import target_to_bits

GENESIS_HEADER = BlockHeader.parse(BytesIO(RAW_GENESIS_BLOCK))
GENESIS_BLOCK = Block.parse(BytesIO(RAW_GENESIS_BLOCK))

starting_bits = target_to_bits(16**62)


class BitcoinNode:
    def __init__(self):
        self.headers = [GENESIS_HEADER]
        self.blocks = [GENESIS_BLOCK]
        self.utxo_set = {}
        self.peer = None

    def connect(self, host, port):
        self.peer = PeerConnection(host, port)
        self.peer.handshake()

    def receive_header(self, header):
        # TODO: verify hash matches
        # TODO: check proof-of-work
        # append block headers received to headers array
        previous = self.headers[-1]
        if header.prev_block != previous.hash():
            raise RuntimeError('discontinuous block at {}'.format(
                len(self.headers)))