def setUp(self):
     self.tp = TransactionPool()
     self.wallet = Wallet()
     self.recipient = 'r3co09ow99'
     self.transaction = Transaction.new_transaction(self.wallet,
                                                    self.recipient, 30)
     self.tp.update_or_add(self.transaction)
示例#2
0
def test_add_same_transaction(blockchain: Blockchain):
    transaction = to_transaction((63, [(63, 27)]))
    block = Block(blockchain.get_last_block(), [transaction])
    block.mine(blockchain.get_difficult())
    blockchain.add(block)
    transactionPool = TransactionPool()
    assert not transactionPool.receive_transaction(blockchain, transaction)
示例#3
0
def test_receive_transaction(transactionPool: TransactionPool,
                             blockchain: Blockchain):
    transaction = to_transaction((63, [(43, 28)]))
    assert transactionPool.receive_transaction(blockchain, transaction)

    transaction = to_transaction((63, [(43, 13)]))
    assert transactionPool.receive_transaction(blockchain, transaction)
示例#4
0
def test_pick_best_transactions(transactionPool: TransactionPool,
                                blockchain: Blockchain):
    transactions = mapv(to_transaction,
                        (((63, [(63, 1)])), (63, [(63, 9)]), (63, [(63, 27)])))
    for i in (2, 0, 1):
        transactionPool.receive_transaction(blockchain, transactions[i])
    picked_transactions = transactionPool.get_best_transactions(blockchain, 3)
    indexes = mapv(lambda trans: transactions.index(trans),
                   picked_transactions)
    assert indexes == [0, 1, 2]
示例#5
0
 def __init__(self, genesis_block):
     utxo_pool = UTXOPool()
     self.tx_pool = TransactionPool()
     block_plus_to_add = self.BlockPlus(genesis_block, 1, utxo_pool)
     #        hash_content_byte_wrapper = ByteArrayWrapper(genesis_block.hash);
     hash_content = genesis_block.hash
     self.block_chain = {}
     self.block_chain[hash_content] = block_plus_to_add
     self.last_block_plus = block_plus_to_add
     # if the first guy gets the coinbase
     self.add_coinbase_to_UTXOPool(genesis_block, utxo_pool)
示例#6
0
    def __init__(self, my_port, node_host=None, node_port=None):
        self.my_ip = self.__get_myip()
        print('Server IP address is set to ... ', self.my_ip)
        self.my_port = my_port
        self.cm = ConnectionManager(self.my_ip, self.my_port, self.__handle_message)
        self.node_host = node_host
        self.node_port = node_port
        self.bm = BlockchainManager()
        self.tp = TransactionPool()

        self.clock = 0
        self.status = STATUS_IDLE
        self.next_status = STATUS_IDLE
        self.new_txs = []
        self.end_mining_clock = None
        self.new_block = None
        self.to_port = None
class TestTransactionPool(unittest.TestCase):
    def setUp(self):
        self.tp = TransactionPool()
        self.wallet = Wallet()
        self.recipient = 'r3co09ow99'
        self.transaction = Transaction.new_transaction(self.wallet,
                                                       self.recipient, 30)
        self.tp.update_or_add(self.transaction)

    def test_add_transaction_to_pool(self):
        self.assertEqual(self.tp.transactions[0].id, self.transaction.id)

    def test_update_pool(self):
        old = str(self.transaction.__dict__)
        new = self.transaction.insert_output(self.wallet, 'k5co09ow99', 10)
        self.tp.update_or_add(new)

        self.assertNotEqual(old, str(self.tp.transactions[0].__dict__))

    def test_json_encode(self):
        print(self.tp.to_json())
示例#8
0
                        help='web server port',
                        default=5000,
                        type=int)
    parser.add_argument('p2p_port',
                        help='p2p server port',
                        default=6000,
                        type=int)
    parser.add_argument(
        '-k',
        '--key_location',
        help='location of wallet private key (defaults to "wallet/pk.pem")',
        default='wallet/pk.pem',
        type=str)
    args = parser.parse_args()

    tx_pool = TransactionPool()
    blockchain = Blockchain(tx_pool)
    wallet = Wallet(args.key_location)
    p2p_application = P2PApplication(blockchain)
    blockchain.p2p_application = p2p_application
    web_app.blockchain = blockchain
    web_app.p2p_application = p2p_application
    web_app.wallet = wallet

    print('My pubblic address is: {}'.format(
        bytes_to_hex(wallet.get_public_key())))

    server_url = 'ws://127.0.0.1:{}'.format(args.p2p_port)
    print('Starting p2p server at {}'.format(server_url))
    p2p_application.start_server(server_url)
示例#9
0
def test_transaction_wrong(transactionPool: TransactionPool,
                           blockchain: Blockchain):
    transaction = to_transaction((63, [(43, 29)]))
    assert not transactionPool.receive_transaction(blockchain, transaction)
示例#10
0
def transactionPool() -> TransactionPool:
    transactionPool = TransactionPool()
    return transactionPool
示例#11
0
class BlockChain:
    CUT_OFF_AGE = 10

    class BlockPlus:
        def __init__(self, block, index, utxo_pool):
            self.block = block
            self.index = index
            self.utxo_pool = utxo_pool

        @property
        def utxo_pool(self):
            return self.__utxo_pool

        @utxo_pool.setter
        def utxo_pool(self, val):
            self.__utxo_pool = val

        def get_utxo_pool_copy(self):
            return UTXOPool(self.utxo_pool)

    def __init__(self, genesis_block):
        utxo_pool = UTXOPool()
        self.tx_pool = TransactionPool()
        block_plus_to_add = self.BlockPlus(genesis_block, 1, utxo_pool)
        #        hash_content_byte_wrapper = ByteArrayWrapper(genesis_block.hash);
        hash_content = genesis_block.hash
        self.block_chain = {}
        self.block_chain[hash_content] = block_plus_to_add
        self.last_block_plus = block_plus_to_add
        # if the first guy gets the coinbase
        self.add_coinbase_to_UTXOPool(genesis_block, utxo_pool)

    def get_max_height_block(self):
        return self.last_block_plus.block

    def get_max_height_UTXOPool(self):
        return self.last_block_plus.get_utxo_pool_copy()

    def get_transaction_pool(self):
        return self.tx_pool

    def add_block(self, block):

        # check for parent block hash
        prev_block_hash = block.prev_block_hash
        if prev_block_hash is None:
            return False

        # check for parent block
#        parent_block_plus = self.block_chain.get(ByteArrayWrapper(prev_block_hash))
        parent_block_plus = self.block_chain.get(prev_block_hash)
        if parent_block_plus is None:
            return False

        # validate transactions in current block wrt to its parent block's utxoPool (unspent at parents time can only be spent this time)
        tx_handler = TxHandler(parent_block_plus.get_utxo_pool_copy())
        current_txs = block.txs

        # check all the currentTxs are valid
        # Note: handleTxs() also updates the corresponding utxoPool
        valid_txs = tx_handler.handle_txs(current_txs)
        if len(current_txs) != len(valid_txs):
            return False

        # Looks all good, we can add the block now if it has not reached the cut_off
        # should not be older than CUT_OFF_AGE from last_block_plus
        if (parent_block_plus.index + 1 <=
                self.last_block_plus.index - BlockChain.CUT_OFF_AGE):
            return False

        utxo_pool = tx_handler.get_utxo_pool()
        # update utxo_pool for coinbase tx
        self.add_coinbase_to_utxo_pool(block, utxo_pool)
        block_plus_to_add = self.BlockPlus(block, parent_block_plus.index + 1,
                                           utxo_pool)
        #        self.block_chain[ByteArrayWrapper(block.hashcode)] = block_plus_to_add
        self.block_chain[block.hashcode] = block_plus_to_add
        if parent_block_plus.index + 1 > self.last_block_plus.index:
            self.last_block_plus = block_plus_to_add
        return True

    def add_coinbase_to_utxo_pool(self, block, utxo_pool):
        tx = block.coinbase
        for i, op in enumerate(tx.outputs):
            utxo = UTXO(tx.hashcode, i)
            utxo_pool.append(utxo, op)

    def add_transaction(self, tx):
        self.tx_pool.add_transaction(tx)
示例#12
0
 def setUp(self):
     self.wallet = Wallet()
     self.tp = TransactionPool()
     self.send_amount = 50
     self.recipient = 'r3co09ow99'
示例#13
0
class Node:
    def __init__(self, my_port, node_host=None, node_port=None):
        self.my_ip = self.__get_myip()
        print('Server IP address is set to ... ', self.my_ip)
        self.my_port = my_port
        self.cm = ConnectionManager(self.my_ip, self.my_port, self.__handle_message)
        self.node_host = node_host
        self.node_port = node_port
        self.bm = BlockchainManager()
        self.tp = TransactionPool()

        self.clock = 0
        self.status = STATUS_IDLE
        self.next_status = STATUS_IDLE
        self.new_txs = []
        self.end_mining_clock = None
        self.new_block = None
        self.to_port = None

    def start(self):
        self.cm.start()

    def reset(self):
        self.bm.clear_chain()
        self.tp.clear()
        self.clock = 0
        self.status = STATUS_IDLE
        self.next_status = STATUS_IDLE

    def work(self, clock):
        self.clock = clock
        self.status = self.next_status
        if self.status == STATUS_MINING:
            self.__mine()
        elif self.status == STATUS_BROADCASTED_BLOCK:
            self.__broadcast_block()
        elif self.status == STATUS_BROADCASTED_TX:
            self.__broadcast_tx()
        elif self.status == STATUS_RECEIVED_BLOCK:
            self.__receive_block()
        elif self.status == STATUS_RECEIVED_TX:
            self.__receive_tx()
        elif self.status == STATUS_REQUEST_CHAIN:
            self.__receive_tx()
        elif self.status == STATUS_SENT_CHAIN:
            self.__receive_tx()
        elif self.status == STATUS_RECEIVED_CHAIN:
            self.__receive_tx()

    def __mine(self):
        if self.end_mining_clock is None:
            self.end_mining_clock = self.clock + 2
            self.new_block = self.__generate_block_with_tp()
            print("new block: ", self.new_block)
            self.next_status = STATUS_MINING
        elif self.end_mining_clock > self.clock:
            self.next_status = STATUS_MINING
        else:
            self.bm.set_new_block(self.new_block)
            self.tp.clear()
            self.end_mining_clock = None
            self.next_status = STATUS_BROADCASTED_BLOCK

    def __broadcast_block(self):
        self.cm.broadcast_block(self.new_block)
        self.new_block = None
        self.next_status = STATUS_IDLE

    def __broadcast_tx(self):
        self.cm.broadcast_tx(self.new_txs)
        self.new_txs = []
        self.next_status = STATUS_IDLE

    def __receive_block(self):
        self.bm.set_new_block(self.new_block)
        self.next_status = STATUS_BROADCASTED_BLOCK

    def __receive_tx(self):
        self.tp.set_tx(self.new_txs)
        self.next_status = STATUS_BROADCASTED_TX

    def __request_chain(self):
        self.cm.request_chain(self.to_port)
        self.to_port = None
        self.next_status = STATUS_IDLE

    def __send_chain(self):
        chain_json = self.bm.get_chain_json()
        self.cm.send_chain(chain_json, self.to_port)

    def __received_chain(self):
        self.next_status = STATUS_IDLE

    def __generate_block_with_tp(self):
        txs = self.tp.get_stored_transaction()
        if txs:
            return self.bm.generate_new_block(txs)

    def add_peer(self, peer):
        self.cm.add_peer((peer['addr'], peer['port']))

    def clear_peer(self, peer):
        self.cm.clear_peer((peer['addr'], peer['port']))

    def __handle_message(self, msg):
        if msg[0] == MSG_NEW_BLOCK:
            block_dict = msg[2]
            if block_dict['id'] + 1 <= len(self.bm.chain):
                print("received known block")
                self.next_status = STATUS_IDLE
            else:
                block = Block(block_dict['id'], block_dict['transaction'],
                              block_dict['previous_block_hash'], block_dict['nonce'],
                              block_dict['timestamp'])
                print("received new block", block.to_dict())
                if block.previous_block_hash == self.bm.chain[-1].get_hash():
                    self.new_block = block
                    self.next_status = STATUS_RECEIVED_BLOCK
                else:
                    self.to_port = msg[1]
                    self.next_status = STATUS_REQUEST_CHAIN
        elif msg[0] == MSG_NEW_TX:
            txs = json.loads(msg[2])
            for tx in txs:
                if tx in self.tp.get_stored_transaction():
                    print("received known tx")
                else:
                    print("received new tx", tx)
                    self.new_txs.append(tx)
                    self.next_status = STATUS_RECEIVED_TX
        elif msg[0] == MSG_REQ_CHAIN:
            self.to_port = msg[1]
            self.next_status = STATUS_SENT_CHAIN
        elif msg[0] == MSG_CHAIN:
            self.bm.clear_chain()
            chain = msg[2]
            for block_dict in chain:
                block = Block(block_dict['id'], block_dict['transaction'],
                              block_dict['previous_block_hash'], block_dict['nonce'],
                              block_dict['timestamp'])
                self.bm.set_new_block(block)
            self.next_status = STATUS_RECEIVED_CHAIN

    def join_network(self):
        if self.node_host is not None:
            self.cm.join_network(self.node_host, self.node_port)
        else:
            print('This server is running as Genesis Node ...')

    def get_current_status(self):
        return self.status

    def __get_myip(self):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(('8.8.8.8', 80))
        return s.getsockname()[0]

    def get_status(self):
        data = json.dumps(
            {
                "clock": self.clock,
                "status": self.status
            }
        ).encode("utf-8")
        return data

    def get_peers(self):
        data = json.dumps(self.cm.peers).encode('utf-8')
        return data

    def get_latest_block(self):
        latest_block = self.bm.chain[-1]
        return latest_block.to_json()

    def get_block(self, index):
        chain = self.bm.chain
        if index < len(chain):
            return chain[index].to_json()
        else:
            return None

    def get_all_blocks(self):
        return self.bm.get_chain_json()

    def get_tx_in_pool(self):
        txs = self.tp.get_stored_transaction()
        return json.dumps(txs).encode('utf-8')

    def set_clock(self, clock):
        self.clock = clock
示例#14
0
def create_app(my_ip: str = 'localhost:5000',
               key: int = 1,
               servers: List[str] = []):
    app = Flask(__name__)

    servers = deepcopy(servers)
    blockchain = Blockchain()
    transactionPool = TransactionPool()

    miner_key = PrivateKey(key).public_key().to_bytes()

    def send_my_ip():
        server_data = servers + [my_ip]
        for server in servers:
            requests.post(f'http://{server}/receiveips', \
                          data=dumps(server_data))

    def send_blockchain():
        for server in servers:
            blockArray = BlockArray(blockchain)
            blockchain_bytes = b64encode(pickle.dumps(blockArray))
            requests.post(f'http://{server}/receiveblockchain', \
                          data=blockchain_bytes)

    send_my_ip()

    @app.route('/blockchain')
    def blockchain_web():
        return jsonify(blockchain.to_dict())

    @app.route('/addtransaction', methods=['POST'])
    def add_transaction():
        transaction_dict = request.json
        form = TransactionForm(**transaction_dict)
        if form.validate():
            wallet = Wallet(key)
            transaction = Transaction(outputs=[(PrivateKey(
                transaction_dict['receiver']).public_key().to_bytes(),
                                                transaction_dict['amount'])])
            signed_transaction = wallet.sign(transaction)
            transactionPool.receive_transaction(blockchain, signed_transaction)
            return ''
        return '', 403

    @app.route('/mine')
    def mine():
        if len(blockchain) == 0:
            genesis_block = GenesisBlock(miner_pub_key=miner_key)
            genesis_block.mine(blockchain.get_difficult())
            blockchain.add(genesis_block)
        else:
            block = Block(previous_block=blockchain.chain[-1], miner_pub_key=miner_key, \
                transactions=transactionPool.get_best_transactions(blockchain,1))
            block.mine(blockchain.get_difficult())
            blockchain.add(block)
        send_blockchain()
        return ''

    @app.route('/receiveblockchain', methods=['POST'])
    def receive_blockchain():
        blockArray = pickle.loads(b64decode(request.data))
        if isinstance(blockArray, BlockArray):
            len_before = len(blockchain)
            blockchain.substitute(blockArray)
            len_after = len(blockchain)
            if len_after > len_before:
                send_blockchain()
            return ''
        return '', 403

    @app.route('/receiveips', methods=['POST'])
    def receive_ips():
        ips = loads(request.data.decode('utf-8'))
        if isinstance(ips, list):
            for ip in ips:
                if ip not in servers and ip != my_ip:
                    servers.append(ip)
        return ''

    @app.route('/getips')
    def get_ips():
        return jsonify(servers)

    return app
示例#15
0
import logging
import threading
import base64

from flask import Flask, request, jsonify, redirect

from blockchain import Blockchain
from p2p import MyOwnPeer2PeerNode
from wallet import Wallet
from transaction_pool import TransactionPool

app = Flask(__name__)

bc = Blockchain()
wallet = Wallet()
tp = TransactionPool()

# Use diffierent ports to simulate nodes in my development environment.
# It will be distinguish by ip address in real world.
HTTP_PORT = os.environ[
    "HTTP_PORT"] if 'HTTP_PORT' in os.environ else 3000  # export HTTP_PORT=3001
P2P_PORT = int(os.environ["P2P_PORT"]
               ) if 'P2P_PORT' in os.environ else 5001  # export P2P_PORT=5002
node = MyOwnPeer2PeerNode("127.0.0.1", int(P2P_PORT), bc)


@app.route('/blocks')
def blocks():
    j = bc.to_json()
    return j