Ejemplo n.º 1
0
    def test_valid_merkle_one_leaf(self):

        tx1 = Transaction([], [TransactionOutput("Alice", "Bob", 1), TransactionOutput("Alice", "Alice", 1)])
        transactions = [tx1]
        block = TestBlock(0, transactions, "genesis", is_genesis=True)
        expected_value = sha256_2_string(str(tx1))
        self.assertEqual(block.calculate_merkle_root(), expected_value)
    def test_input_txs_in_block(self):
        tx1 = Transaction([], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Alice", 1)
        ])

        # create chain of transactions; tx2 spends tx1, tx3 spends tx2
        tx2 = Transaction([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", .9),
            TransactionOutput("Alice", "Carol", 0)
        ])
        tx3 = Transaction([tx2.hash + ":0"],
                          [TransactionOutput("Bob", "Bob", .8)])

        block = TestBlock(0, [tx1], "genesis", is_genesis=True)
        self.assertTrue(block.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block))

        block2 = TestBlock(1, [tx2], block.hash)
        self.assertTrue(block2.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block2))

        block3 = TestBlock(1, [tx3], block.hash)
        self.assertEqual(block3.is_valid(),
                         (False, "Input transaction not found"))

        block3 = TestBlock(1, [tx2, tx3], block.hash)
        self.assertTrue(block3.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block3))
    def test_rejects_invalid_hash(self):
        tx1 = Transaction([], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Alice", 1)
        ])
        tx2 = Transaction([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", .4),
            TransactionOutput("Alice", "Carol", .4)
        ])

        # test an invalid hash on genesis block is rejected, and valid hash is accepted
        block = TestBlock(0, [tx1], "genesis", is_genesis=True)
        self.assertTrue(block.is_valid()[0])
        self.test_chain.add_block(block)
        old_hash = block.hash
        block.hash = "fff"
        self.assertEqual(block.is_valid(), (False, "Hash failed to match"))
        block.hash = old_hash

        # test an invalid hash on non-genesis block is rejected, and valid hash is accepted
        block2 = TestBlock(1, [tx2], block.hash)
        self.assertTrue(block2.is_valid()[0])
        old_hash = block2.hash
        block2.hash = "fff"
        self.assertEqual(block2.is_valid(), (False, "Hash failed to match"))
        block2.hash = old_hash
        self.assertTrue(block2.is_valid()[0])
Ejemplo n.º 4
0
    def test_input_txs_on_chain(self):
        tx1 = Transaction([], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Alice", 1)
        ])

        # next two transactions spend same input twice (double spend)
        tx2 = Transaction([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", .9),
            TransactionOutput("Alice", "Carol", 0)
        ])
        tx3 = Transaction([tx2.hash + ":0"],
                          [TransactionOutput("Bob", "Bob", .8)])

        block = TestBlock(0, [tx1], "genesis", is_genesis=True)
        self.assertTrue(block.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block))

        block2 = TestBlock(1, [tx2], block.hash)
        self.assertTrue(block2.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block2))

        block3 = TestBlock(1, [tx3], block.hash)
        self.assertEqual(block3.is_valid(),
                         (False, "Input transaction not found"))

        block3 = TestBlock(2, [tx3], block2.hash)
        self.assertTrue(block3.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block3))
Ejemplo n.º 5
0
 def test_valid_merkle_three_leafs(self):
     tx1 = Transaction([], [TransactionOutput("Alice", "Bob", 1), TransactionOutput("Alice", "Alice", 1)])
     tx2 = Transaction([tx1.hash + ":1"],
                       [TransactionOutput("Alice", "Bob", .9), TransactionOutput("Alice", "Carol", 0)])
     tx3 = Transaction([tx2.hash + ":0"], [TransactionOutput("Bob", "Bob", .8)])
     transactions = [tx1, tx2, tx3]
     block = TestBlock(0, transactions, "genesis", is_genesis=True)
     expected_value = sha256_2_string(sha256_2_string(str(tx1)) + sha256_2_string(str(tx2)))
     expected_value = sha256_2_string(expected_value + sha256_2_string(str(tx3)))
     self.assertEqual(block.calculate_merkle_root(), expected_value)
Ejemplo n.º 6
0
 def test_blockchain_hash(self):
     tx1 = Transaction([], [
         TransactionOutput("Alice", "Bob", 1),
         TransactionOutput("Alice", "Alice", 1)
     ])
     tx2 = Transaction([tx1.hash + ":0"], [
         TransactionOutput("Alice", "Bob", 1),
         TransactionOutput("Alice", "Carol", 1)
     ])
     block = TestBlock(0, [tx1, tx2], "genesis", is_genesis=True)
     block.set_dummy_vals()
     self.assertEqual(
         sha256_2_string(block.header()),
         "b0d35a2ffb46c6a8f48658d77f990656f7a9ec753b77342eb3b0e6a1d7acf934")
Ejemplo n.º 7
0
    def test_merkle_root(self):
        tx1 = Transaction([], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Alice", 3)
        ])
        tx2 = Transaction([tx1.hash + ":0"], [
            TransactionOutput("Alice", "Bob", 2),
            TransactionOutput("Alice", "Carol", 1)
        ])
        tx3 = Transaction([tx2.hash + ":0"], [
            TransactionOutput("Bob", "Carol", 1),
            TransactionOutput("Bob", "Bob", 1)
        ])
        tx4 = Transaction([tx3.hash + ":0"], [
            TransactionOutput("Carol", "Alice", 0.5),
            TransactionOutput("Carol", "Carol", 0.5)
        ])

        block1 = TestBlock(0, [tx1], "genesis", is_genesis=True)
        block2 = TestBlock(0, [tx1, tx2], "genesis", is_genesis=True)
        block3 = TestBlock(0, [tx1, tx2, tx3, tx4], "genesis", is_genesis=True)

        for block in [block1, block2, block3]:
            block.set_dummy_timestamp()

        self.assertEqual(
            block1.merkle,
            "70dd3a969ee311d9749d8f1c2f03ab1dc4930ca0be58d231a73dfeeb85f5b68d")
        self.assertEqual(
            block2.merkle,
            "e0559c662f64c8fd1b638384ecbb1104335445a07114fd7d197316402e2f6f4c")
        self.assertEqual(
            block3.merkle,
            "039eceb401b485400f19bca99158b9dd2fcd13e9e4f287fde16f81fa58074a51")
Ejemplo n.º 8
0
 def test_blockchain_hash(self):
     tx1 = Transaction([], [
         TransactionOutput("Alice", "Bob", 1),
         TransactionOutput("Alice", "Alice", 1)
     ])
     tx2 = Transaction([tx1.hash + ":0"], [
         TransactionOutput("Alice", "Bob", 1),
         TransactionOutput("Alice", "Carol", 1)
     ])
     block = TestBlock(0, [tx1, tx2], "genesis", is_genesis=True)
     block.set_dummy_timestamp()
     self.assertEqual(
         sha256_2_string(block.header()),
         "9fc4ae4f2e6a68a0e79a57c4491b03a72f9a4bcdbc6ab7213e0f9334d800c57d")
    def test_double_tx_inclusion_same_block(self):
        tx1 = Transaction([], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Alice", 1)
        ])
        tx2 = Transaction([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", .4),
            TransactionOutput("Alice", "Carol", .4)
        ])

        block = TestBlock(0, [tx1], "genesis", is_genesis=True)
        self.assertTrue(block.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block))

        block2 = TestBlock(1, [tx2, tx2], block.hash)
        self.assertEqual(block2.is_valid(),
                         (False, "Double transaction inclusion"))
    def test_doublespent_input_same_chain(self):
        tx1 = Transaction([], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Alice", 1)
        ])

        # next two transactions spend same input twice (double spend)
        tx2 = Transaction([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", 0),
            TransactionOutput("Alice", "Carol", 0)
        ])
        tx3 = Transaction([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Carol", 0),
            TransactionOutput("Alice", "Carol", 0)
        ])

        block = TestBlock(0, [tx1], "genesis", is_genesis=True)
        self.assertTrue(block.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block))

        block2 = TestBlock(1, [tx2], block.hash)
        self.assertTrue(block2.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block2))

        block3 = TestBlock(2, [tx3], block2.hash)
        self.assertEqual(block3.is_valid(), (False, "Double-spent input"))

        block3 = TestBlock(1, [tx3], block.hash)
        self.assertTrue(
            block3.is_valid()[0])  # doublespend should be allowed across forks
Ejemplo n.º 11
0
    def test_failed_input_lookup(self):
        tx1 = Transaction([], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Alice", 1)
        ])
        tx2 = Transaction([tx1.hash + ":2"], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Carol", 1)
        ])  # good tx id, bad input location
        tx3 = Transaction(["fakehash" + ":2"], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Carol", 1)
        ])  # bad tx id

        block = TestBlock(0, [tx1], "genesis", is_genesis=True)
        self.assertTrue(block.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block))

        block2 = TestBlock(1, [tx2], block.hash)
        self.assertEqual(block2.is_valid(),
                         (False, "Required output not found"))

        block2 = TestBlock(1, [tx3], block.hash)
        self.assertEqual(block2.is_valid(),
                         (False, "Required output not found"))
    def test_rejects_too_many_txs(self):
        txs = []

        for i in range(901):
            txs.append(
                Transaction([], [
                    TransactionOutput("Alice", "Bob", 1),
                    TransactionOutput("Alice", "Alice", 1)
                ]))

        # test too many txs in genesis
        block = TestBlock(0, txs, "genesis", is_genesis=True)
        self.assertEqual(block.is_valid(), (False, "Too many transactions"))

        # 900 txs should be fine
        block = TestBlock(0, txs[1:], "genesis", is_genesis=True)
        self.assertTrue(block.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block))

        # test too many txs outside genesis
        block = TestBlock(1, txs, block.hash)
        self.assertEqual(block.is_valid(), (False, "Too many transactions"))
    def test_user_consistency(self):
        tx1 = Transaction([], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Alice", 1)
        ])
        tx2 = Transaction(
            [tx1.hash + ":1"], [
                TransactionOutput("Carol", "Bob", 0),
                TransactionOutput("Carol", "Carol", 0)
            ]
        )  # outputs created from wrong user (different than one that received inputs)
        tx3 = Transaction([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", 0),
            TransactionOutput("Carol", "Carol", 0)
        ])  # two outputs from different users
        tx4 = Transaction([tx1.hash + ":0", tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", 0),
            TransactionOutput("Alice", "Carol", 0)
        ])  # two inputs to different users
        tx5 = Transaction([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", 0),
            TransactionOutput("Alice", "Carol", 0)
        ])  # this one is valid

        block = TestBlock(0, [tx1], "genesis", is_genesis=True)
        self.assertTrue(block.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block))

        block2 = TestBlock(1, [tx2], block.hash)
        self.assertEqual(block2.is_valid(), (False, "User inconsistencies"))

        block2 = TestBlock(1, [tx3], block.hash)
        self.assertEqual(block2.is_valid(), (False, "User inconsistencies"))

        block2 = TestBlock(1, [tx4], block.hash)
        self.assertEqual(block2.is_valid(), (False, "User inconsistencies"))

        block2 = TestBlock(1, [tx5], block.hash)
        self.assertTrue(block2.is_valid()[0])
    def test_failed_input_lookup(self):
        tx1 = Transaction([], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Alice", 1)
        ])
        tx2 = Transaction([tx1.hash + ":2"], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Carol", 1)
        ])  # good tx id, bad input location
        tx3 = Transaction(["fakehash" + ":2"], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Carol", 1)
        ])  # bad tx id
        # good txs
        tx4 = Transaction([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", .2),
            TransactionOutput("Alice", "Carol", .2)
        ])
        tx5 = Transaction([tx4.hash + ":0"],
                          [TransactionOutput("Bob", "Bob", 0)])

        block = TestBlock(0, [tx1], "genesis", is_genesis=True)
        self.assertTrue(block.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block))

        block2 = TestBlock(1, [tx2], block.hash)
        self.assertEqual(block2.is_valid(),
                         (False, "Required output not found"))

        block2 = TestBlock(1, [tx3], block.hash)
        self.assertEqual(block2.is_valid(),
                         (False, "Required output not found"))

        block2 = TestBlock(
            1, [tx4, tx5],
            block.hash)  # tx exists, but is in same block; this should work
        self.assertTrue(block2.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block2))
Ejemplo n.º 15
0
def string_to_output(outputstring):
    """ Takes a string as input and deserializes it into a
        transaction object for receipt over network.
        !!! WARNING !!!
        (don't ever do anything like this in production, it's not secure).

        Args:
            outputstring (str): Transaction output represented as a string.

        Returns:
            :obj:`TransactionOutput`: Parsed transaction output,
            False or exception thrown on failure.
    """

    output_parts = outputstring.split("~")
    if len(output_parts) != 3:
        return False

    return TransactionOutput(output_parts[0], output_parts[1], int(output_parts[2]))
    def test_no_money_creation(self):
        tx1 = Transaction([], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Alice", 1)
        ])
        tx2 = Transaction([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", 3),
            TransactionOutput("Alice", "Carol", 0)
        ])  # single output creates money
        tx3 = Transaction([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", .9),
            TransactionOutput("Alice", "Carol", .9)
        ])  # sum of outputs creates money

        block = TestBlock(0, [tx1], "genesis", is_genesis=True)
        self.assertTrue(block.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block))

        block2 = TestBlock(1, [tx2], block.hash)
        self.assertEqual(block2.is_valid(), (False, "Creating money"))

        block2 = TestBlock(1, [tx3], block.hash)
        self.assertEqual(block2.is_valid(), (False, "Creating money"))
    def test_malformed_txs(self):
        tx1 = Transaction([], [
            TransactionOutput("Alice", "Bob", 1),
            TransactionOutput("Alice", "Alice", 1)
        ])
        tx2_evil = BadTX([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", .4),
            TransactionOutput("Alice", "Carol", .4)
        ])
        tx2 = Transaction([tx1.hash + ":1"], [
            TransactionOutput("Alice", "Bob", .4),
            TransactionOutput("Alice", "Carol", .4)
        ])

        block = TestBlock(0, [tx1], "genesis", is_genesis=True)
        self.assertTrue(block.is_valid()[0])
        self.assertTrue(self.test_chain.add_block(block))

        block2 = TestBlock(1, [tx2_evil], block.hash)
        self.assertEqual(block2.is_valid(),
                         (False, "Malformed transaction included"))

        block2 = TestBlock(1, [tx2], block.hash)
        self.assertTrue(block2.is_valid()[0])
Ejemplo n.º 18
0
from p2p import gossip

USERS = ["Alice", "Bob", "Charlie", "Dave", "Errol", "Frank"]
HEIGHT_TO_REACH = 100
MAX_TXS_PER_BLOCK = 50
FORK_PROBABILITY = .3

# basic wallet functionality; track UTXOs for users
user_utxos = {}
for user in USERS:
    user_utxos[user] = []

# insert genesis block; populate all users w huge balance
outputs = []
for user in USERS:
    genesis_utxo = TransactionOutput("Genesis", user, 100000000)
    outputs.append(genesis_utxo)
genesis_tx = Transaction([], outputs)
for user_num in range(len(USERS)):
    user = USERS[user_num]
    user_utxos[user].append((genesis_tx.hash + ":" + str(user_num), 100000000))
genesis_block = PoWBlock(0, [genesis_tx], "genesis", is_genesis=True)
chaindb.chain.add_block(genesis_block)

gossip.gossip_message("addblock", genesis_block)

curr_height = 1
parent = genesis_block

while curr_height <= HEIGHT_TO_REACH:
    chain = chaindb.chain
Ejemplo n.º 19
0
import blockchain
from blockchain.transaction import Transaction, TransactionOutput
from blockchain.pow_block import PoWBlock
import transaction

# create some transactions
tx1 = Transaction([], [
    TransactionOutput("Alice", "Bob", 1),
    TransactionOutput("Alice", "Alice", 1)
])
tx2 = Transaction([tx1.hash + ":0"], [
    TransactionOutput("Alice", "Bob", .4),
    TransactionOutput("Alice", "Carol", .4)
])

# create an unsealed block
block = PoWBlock(0, [tx1, tx2], "genesis", is_genesis=True)

# run the mining loop until a valid PoW seal is created (final hash should have 2 leading 0s)
block.mine()

# add the block to the blockchain
assert (blockchain.chain.add_block(block))

# display the block
print(block.header())
print(block.hash)