예제 #1
0
    def __mine(self, mempool: Set[Transaction], chain: Chain,
               wallet: Wallet) -> Block:
        c_pool = list(copy.deepcopy(mempool))
        mlist = self.__calculate_transactions(c_pool)
        logger.debug(len(mlist))

        block_header = BlockHeader(
            version=consts.MINER_VERSION,
            height=chain.length,
            prev_block_hash=dhash(chain.header_list[-1]),
            merkle_root=merkle_hash(mlist),
            timestamp=int(time.time()),
            signature="",
        )

        sign = wallet.sign(dhash(block_header))
        block_header.signature = sign
        block = Block(header=block_header, transactions=mlist)
        r = requests.post("http://0.0.0.0:" + str(consts.MINER_SERVER_PORT) +
                          "/newblock",
                          data=compress(block.to_json()))
        if r.text == "Block Received":
            vjti_chain_relayer = VJTIChainRelayer(wallet)
            vjti_chain_relayer.new_block(block)
            logger.info(f"Miner: Mined Block with {len(mlist)} transaction(s)")
            return block
        else:
            logger.info(
                f"Miner: Could not mine block with {len(mlist)} transaction(s)"
            )
            return None
예제 #2
0
def render_block_header(hdr):
    html = "<table>"

    html += "<tr><th>" + "Height" + "</th>"
    html += "<td>" + str(hdr.height) + "</td></tr>"

    html += "<tr><th>" + "Block Hash" + "</th>"
    html += "<td>" + dhash(hdr) + "</td></tr>"

    html += "<tr><th>" + "Prev Block Hash" + "</th>"
    html += "<td>" + str(hdr.prev_block_hash) + "</td></tr>"

    html += "<tr><th>" + "Merkle Root" + "</th>"
    html += "<td>" + str(hdr.merkle_root) + "</td></tr>"

    html += "<tr><th>" + "Timestamp" + "</th>"
    html += ("<td>" + str(
        datetime.fromtimestamp(hdr.timestamp).strftime("%d-%m-%Y %H:%M:%S")) +
             " (" + str(hdr.timestamp) + ")</td></tr>")

    # get block
    block = Block.from_json(get_block_from_db(dhash(hdr))).object()

    html += "<tr><th>" + "Transactions" + "</th>"
    html += "<td>" + str(len(block.transactions)) + "</td></tr>"

    # for i, transaction in enumerate(block.transactions):
    #     s = "coinbase: " + str(transaction.is_coinbase) + ", fees: " + str(transaction.fees)
    #     html += "<tr><th>Transaction " + str(i) + "</th><td>" + str(s) + "</td></tr>"

    html += "</table>"
    return str(html)
예제 #3
0
    def add_block(self, block: Block, is_genesis: bool) -> bool:
        if is_genesis or self.is_block_valid(block):
            self.header_list.append(block.header)
            self.update_utxo(block)
            self.length = len(self.header_list)
            add_block_to_db(block)
            for tx in block.transactions:
                pub_key, data = tx.summarize()
                for address in data:
                    amount = data[address]
                    timestamp = tx.timestamp
                    bhash = dhash(block.header)
                    thash = dhash(tx)
                    message = tx.message
                    history = generate_tx_hist(amount, pub_key, timestamp,
                                               bhash, thash, message)
                    self.transaction_history.append(address, history)

                    history = generate_tx_hist(-amount, address, timestamp,
                                               bhash, thash, message)
                    self.transaction_history.append(pub_key, history)

            logger.info("Chain: Added Block " + str(block))
            return True
        return False
예제 #4
0
    def is_block_valid(self, block: Block):
        # Check if the block is valid -1

        local_utxo = copy.deepcopy(self.utxo)

        if not block.is_valid():
            logger.debug("Block is not valid")
            return False

        # Ensure the prev block header matches the previous block hash in the Chain -4
        if len(self.header_list) > 0 and not dhash(
                self.header_list[-1]) == block.header.prev_block_hash:
            logger.debug(
                "Chain: Block prev header does not match previous block")
            return False

        # Validating each transaction in block
        for t in block.transactions:
            if self.is_transaction_valid(t):
                thash = dhash(t)
                # Remove the spent outputs
                for tinput in t.vin:
                    so = t.vin[tinput].payout
                    if so:
                        if local_utxo.get(so)[0] is not None:
                            local_utxo.remove(so)
                        else:
                            logger.error(
                                "Chain: Single output missing in UTxO, Transaction invalid"
                            )
                            return False
                    else:
                        logger.error(
                            "Chain: No Single output, Transaction invalid")
                        return False
                # Add new unspent outputs
                for touput in t.vout:
                    local_utxo.set(SingleOutput(txid=thash, vout=touput),
                                   t.vout[touput], block.header)
            else:
                logger.debug("Chain: Transaction not valid")
                return False

        # Validate Authority Signature
        timestamp = datetime.fromtimestamp(block.header.timestamp)
        seconds_since_midnight = (timestamp - timestamp.replace(
            hour=0, minute=0, second=0, microsecond=0)).total_seconds()
        for authority in authority_rules["authorities"]:
            if seconds_since_midnight <= authority[
                    "to"] and seconds_since_midnight >= authority["from"]:
                blk_hdr = copy.deepcopy(block.header)
                blk_hdr.signature = ""
                if Wallet.verify(dhash(blk_hdr), block.header.signature,
                                 authority["pubkey"]):
                    return True
        return False
예제 #5
0
 def __mine(self, mempool: Set[Transaction], chain: Chain,
            payout_addr: str) -> Block:
     c_pool = list(copy.deepcopy(mempool))
     mlist, fees = self.__calculate_best_transactions(c_pool)
     # logger.debug(f"Miner: Will mine {len(mlist)} transactions and get {fees} scoins in fees")
     coinbase_tx_in = {
         0:
         TxIn(payout=None,
              sig="Receiving some Money",
              pub_key="Does it matter?")
     }
     coinbase_tx_out = {
         0: TxOut(amount=chain.current_block_reward(), address=payout_addr),
         1: TxOut(amount=fees, address=payout_addr),
     }
     coinbase_tx = Transaction(
         is_coinbase=True,
         version=consts.MINER_VERSION,
         fees=0,
         timestamp=int(time.time()),
         locktime=-1,
         vin=coinbase_tx_in,
         vout=coinbase_tx_out,
     )
     mlist.insert(0, coinbase_tx)
     block_header = BlockHeader(
         version=consts.MINER_VERSION,
         height=chain.length,
         prev_block_hash=dhash(chain.header_list[-1]),
         merkle_root=merkle_hash(mlist),
         timestamp=int(time.time()),
         target_difficulty=chain.target_difficulty,
         nonce=0,
     )
     DONE = False
     for n in range(2**64):
         block_header.nonce = n
         bhash = dhash(block_header)
         if chain.is_proper_difficulty(bhash):
             block = Block(header=block_header, transactions=mlist)
             requests.post("http://0.0.0.0:" +
                           str(consts.MINER_SERVER_PORT) + "/newblock",
                           data=compress(block.to_json()))
             logger.info(
                 f"Miner: Mined Block with {len(mlist)} transactions, Got {fees} in fees and {chain.current_block_reward()} as reward"
             )
             DONE = True
             break
     if not DONE:
         logger.error(
             "Miner: Exhausted all 2 ** 64 values without finding proper hash"
         )
예제 #6
0
    def remove_transactions_from_mempool(self, block: Block):
        """Removes transaction from the mempool based on a new received block

        Arguments:
            block {Block} -- The block which is received
        """
        new_mempool = set()
        for x in self.mempool:
            DONE = True
            for t in block.transactions:
                if dhash(x) == dhash(t):
                    DONE = False
            if DONE:
                new_mempool.add(x)
        self.mempool = new_mempool
예제 #7
0
def send_block_hashes():
    peer_height = int(request.form.get("myheight"))
    hash_list = []
    for i in range(peer_height, ACTIVE_CHAIN.length):
        hash_list.append(dhash(ACTIVE_CHAIN.header_list[i]))
    logger.debug(peer_height)
    return jsonify(hash_list)
예제 #8
0
def process_new_block(request_data: bytes) -> str:
    global BLOCKCHAIN
    block_json = decompress(request_data)
    if block_json:
        try:
            block = Block.from_json(block_json).object()
            # Check if block already exists
            if get_block_from_db(dhash(block.header)):
                logger.info("Server: Received block exists, doing nothing")
                return "Block already Received Before"
            if BLOCKCHAIN.add_block(block):
                logger.info(
                    "Server: Received a New Valid Block, Adding to Chain")

                logger.debug("Server: Sending new block to peers")
                # Broadcast block to other peers
                send_to_all_peers("/newblock", request_data)
            else:
                return "Block Received, but was not added, due to some error"
        except Exception as e:
            logger.error("Server: New Block: invalid block received " + str(e))
            return "Invalid Block Received"

        # Kill Miner
        t = Timer(1, miner.stop_mining)
        t.start()
        return "Block Received"
    logger.error("Server: Invalid Block Received")
    return "Invalid Block"
예제 #9
0
 def build_from_header_list(cls, hlist: List[BlockHeader]):
     nchain = cls()
     nchain.header_list = []
     for header in hlist:
         block = Block.from_json(get_block_from_db(dhash(header))).object()
         nchain.add_block(block)
     return nchain
예제 #10
0
def send_block_hashes():
    log_ip(request, inspect.stack()[0][3])
    peer_height = int(request.forms.get("myheight"))
    hash_list = []
    for i in range(peer_height, BLOCKCHAIN.active_chain.length):
        hash_list.append(dhash(BLOCKCHAIN.active_chain.header_list[i]))
    return compress(json.dumps(hash_list)).decode()
예제 #11
0
def sendinfo():
    log_ip(request, inspect.stack()[0][3])
    s = ("No. of Blocks: " + str(BLOCKCHAIN.active_chain.length) + "<br>" +
         dhash(BLOCKCHAIN.active_chain.header_list[-1]) + "<br>" + "Balance " +
         str(check_balance(MY_WALLET.public_key)) + "<br>Public Key: <br>" +
         str(get_wallet_from_db(consts.MINER_SERVER_PORT)[1]))
    return s
예제 #12
0
def send_block_hashes():
    peer_height = int(request.forms.get("myheight"))
    hash_list = []
    for i in range(peer_height, BLOCKCHAIN.active_chain.length):
        hash_list.append(dhash(BLOCKCHAIN.active_chain.header_list[i]))
    # logger.debug("Server: Sending Peer this Block Hash List: " + str(hash_list))
    return compress(json.dumps(hash_list)).decode()
예제 #13
0
    def add_block(self, block: Block):
        # if check_block_in_db(dhash(block.header)):
        #     logger.debug("Chain: AddBlock: Block already exists")
        #     return True

        blockAdded = False

        for chain in self.chains:
            if chain.length == 0 or block.header.prev_block_hash == dhash(
                    chain.header_list[-1]):
                if chain.add_block(block):
                    BlockChain.block_ref_count[dhash(block.header)] += 1
                    self.update_active_chain()
                    if chain is self.active_chain:
                        # Remove the transactions from MemPool
                        self.remove_transactions_from_mempool(block)
                    blockAdded = True

        if blockAdded:
            return True

        # Check if we need to fork
        self.chains.sort(key=attrgetter("length"), reverse=True)
        new_chains = copy.deepcopy(self.chains)
        for chain in new_chains:
            hlist = copy.deepcopy(chain.header_list)
            for h in reversed(hlist):
                # Check if block can be added for current header
                if dhash(h) == block.header.prev_block_hash:
                    newhlist = []
                    for hh in chain.header_list:
                        newhlist.append(hh)
                        if dhash(hh) == block.header.prev_block_hash:
                            break

                    nchain = Chain.build_from_header_list(newhlist)
                    if nchain.add_block(block):
                        for header in nchain.header_list:
                            BlockChain.block_ref_count[dhash(header)] += 1
                        if nchain not in self.chains:
                            self.chains.append(nchain)
                        self.update_active_chain()
                        logger.debug(
                            f"There was a soft fork and a new chain was created with length {nchain.length}"
                        )
                        return True
        return False
예제 #14
0
    def update_active_chain(self):
        self.active_chain = max(self.chains, key=attrgetter("length"))
        max_length = self.active_chain.length
        # Try removing old chains
        new_chains = []
        for chain in self.chains:
            if chain.length > max_length - consts.FORK_CHAIN_HEIGHT:
                new_chains.append(chain)
            else:
                for hdr in chain.header_list:
                    if BlockChain.block_ref_count[dhash(hdr)] == 1:
                        del BlockChain.block_ref_count[dhash(hdr)]
                        remove_block_from_db(dhash(hdr))
                    else:
                        BlockChain.block_ref_count[dhash(hdr)] -= 1

        self.chains = new_chains
        # Save Active Chain to DB
        write_header_list_to_db(self.active_chain.header_list)
예제 #15
0
def sendinfo():
    s = ("No. of Blocks: " + str(BLOCKCHAIN.active_chain.length) + "<br>" +
         dhash(BLOCKCHAIN.active_chain.header_list[-1]) + "<br>" +
         "Number of chains " + str(len(BLOCKCHAIN.chains)) + "<br>" +
         "Balance " + str(check_balance()) + "<br>" + "Difficulty: " +
         str(BLOCKCHAIN.active_chain.target_difficulty) + "<br>Block reward " +
         str(BLOCKCHAIN.active_chain.current_block_reward()) +
         "<br>Public Key: <br>" +
         str(get_wallet_from_db(consts.MINER_SERVER_PORT)[1]))
    return s
예제 #16
0
def explorer():
    log_ip(request, inspect.stack()[0][3])
    prev = int(request.query.prev or 0)
    if prev < 0:
        prev = 0
    hdr_list = list(reversed(BLOCKCHAIN.active_chain.header_list))
    indexes = [i for i in range(prev * 8, (prev + 1) * 8) if i < len(hdr_list)]
    blocks = [Block.from_json(get_block_from_db(dhash(hdr_list[i]))).object() for i in indexes]
    transactions = list(BLOCKCHAIN.mempool)
    return template("explorer.html", blocks=blocks, transactions=transactions, prev=prev)
예제 #17
0
 def update_utxo(self, block: Block):
     block_transactions: List[Transaction] = block.transactions
     for t in block_transactions:
         thash = dhash(t)
         # Remove the spent outputs
         for tinput in t.vin:
             so = t.vin[tinput].payout
             if so:
                 self.utxo.remove(so)
         # Add new unspent outputs
         for toutput in t.vout:
             self.utxo.set(SingleOutput(txid=thash, vout=toutput), t.vout[toutput], block.header)
예제 #18
0
    def add_block(self, block: Block) -> bool:
        blockAdded = False

        chain = self.active_chain
        is_genesis = chain.length == 0
        if is_genesis or block.header.prev_block_hash == dhash(chain.header_list[-1]):
            if chain.add_block(block, is_genesis):
                self.update_active_chain()
                self.remove_transactions_from_mempool(block)
                blockAdded = True

        return blockAdded
예제 #19
0
def visualize_chain():
    data = []
    start = BLOCKCHAIN.active_chain.length - 10 if BLOCKCHAIN.active_chain.length > 10 else 0
    for i, chain in enumerate(BLOCKCHAIN.chains):
        headers = []

        if len(chain.header_list) > 200:
            for hdr in chain.header_list[:100]:
                d = {}
                d["hash"] = dhash(hdr)[-5:]
                d["time"] = hdr.timestamp
                d["data"] = render_block_header(hdr)
                d["height"] = hdr.height
                headers.append(d)
        for hdr in chain.header_list[-100:]:
            d = {}
            d["hash"] = dhash(hdr)[-5:]
            d["time"] = hdr.timestamp
            d["data"] = render_block_header(hdr)
            d["height"] = hdr.height
            headers.append(d)
        data.append(headers)
    return template("chains.html", data=data, start=start)
예제 #20
0
def visualize_chain():
    log_ip(request, inspect.stack()[0][3])
    data = []
    start = BLOCKCHAIN.active_chain.length - 10 if BLOCKCHAIN.active_chain.length > 10 else 0
    headers = []
    hdr_list = BLOCKCHAIN.active_chain.header_list
    if len(hdr_list) > 200:
        hdr_list = BLOCKCHAIN.active_chain.header_list[:100] + BLOCKCHAIN.active_chain.header_list[-100:]
    for hdr in hdr_list:
        d = {}
        d["hash"] = dhash(hdr)[-5:]
        d["time"] = hdr.timestamp
        d["data"] = render_block_header(hdr)
        headers.append(d)
    data.append(headers)
    return template("chains.html", data=data, start=start)
예제 #21
0
    def is_block_valid(self, block: Block):
        # Check if the block is valid -1
        if not block.is_valid():
            logger.debug("Block is not valid")
            return False

        # Block hash should have proper difficulty -2
        if not block.header.target_difficulty >= self.target_difficulty:
            logger.debug("Chain: BlockHeader has invalid difficulty")
            return False
        if not self.is_proper_difficulty(dhash(block.header)):
            logger.debug("Chain: Block has invalid POW")
            return False

        # Block should not have been mined more than 2 hours in the future -3
        difference = get_time_difference_from_now_secs(block.header.timestamp)
        if difference > consts.BLOCK_MAX_TIME_FUTURE_SECS:
            logger.debug("Block: Time Stamp not valid")
            return False

        # Reject if timestamp is the median time of the last 11 blocks or before -5
        if len(self.header_list) > 11:
            last_11 = self.header_list[-11:]
            last_11_timestamp = []
            for bl in last_11:
                last_11_timestamp.append(bl.timestamp)
            med = median(last_11_timestamp)
            if block.header.timestamp <= med:
                logger.debug("Chain: Median time past")
                return False

        # Ensure the prev block header matches the previous block hash in the Chain -4
        if len(self.header_list) > 0 and not dhash(
                self.header_list[-1]) == block.header.prev_block_hash:
            logger.debug(
                "Chain: Block prev header does not match previous block")
            return False

        # Validating each transaction in block
        for tx in block.transactions:
            if not self.is_transaction_valid(tx):
                logger.debug("Chain: Transaction not valid")
                return False

        # Validate that the first coinbase Transaction has valid Block reward and fees
        remaining_transactions = block.transactions[1:]
        fee_total = 0
        for tx in remaining_transactions:
            if not self.is_transaction_valid(tx):
                logger.debug("Chain: Transaction not valid")
                return False
            else:
                fee_total += tx.fees
        if not len(block.transactions[0].vout) == 2:
            logger.debug("Chain: Coinbase vout length != 2")
            return False

        if not block.transactions[0].vout[1].amount == fee_total:
            logger.debug("Chain: Coinbase fee invalid")
            return False

        if not block.transactions[0].vout[
                0].amount == self.current_block_reward():
            logger.debug("Chain: Coinbase reward invalid")
            return False
        return True
예제 #22
0
 def build_utxo(self):
     for header in self.header_list:
         block = Block.from_json(get_block_from_db(dhash(header))).object()
         self.update_utxo(block)
예제 #23
0
from utils.utils import dhash


def is_proper_difficulty(target_difficulty, bhash: str) -> bool:
    pow = 0
    for c in bhash:
        if not c == "0":
            break
        else:
            pow += 1
    if pow < target_difficulty:
        return False
    return True


print(genesis_block, dhash(genesis_block_header))

for difficulty in range(5, 10):
    tss = time.time()
    for n in range(2 ** 64):
        genesis_block_header.nonce = n
        genesis_block_header.target_difficulty = difficulty
        bhash = dhash(genesis_block_header)
        if is_proper_difficulty(difficulty, bhash):
            print(f"Timestamp {int(tss)} Nonce {n} hash {bhash}\n Difficulty {difficulty} in {(time.time() - tss)} secs")
            print(genesis_block_header)
            DONE = True
            break
    if not DONE:
        print("Miner: Exhausted all 2 ** 64 values without finding proper hash")
예제 #24
0
 def __hash__(self):
     return int(dhash(self), 16)
예제 #25
0
def get_block_header_hash(height):
    return dhash(BLOCKCHAIN.active_chain.header_list[height])
예제 #26
0
 def __repr__(self):
     return dhash(self.header)
예제 #27
0
 def hash(self):
     return dhash(self)
예제 #28
0
 def __eq__(self, other):
     for i, h in enumerate(self.header_list):
         if dhash(h) != dhash(other.header_list[i]):
             return False
     return True
예제 #29
0
        return get_block_from_db(hhash)
    return "Hash hi nahi bheja LOL"


@app.route("/getblockhashes", methods=["POST"])
def send_block_hashes():
    peer_height = int(request.form.get("myheight"))
    hash_list = []
    for i in range(peer_height, ACTIVE_CHAIN.length):
        hash_list.append(dhash(ACTIVE_CHAIN.header_list[i]))
    logger.debug(peer_height)
    return jsonify(hash_list)


# The singleOutput for first coinbase transaction in genesis block
so = SingleOutput(txid=dhash(genesis_block_transaction[0]), vout=0)

first_block_transactions = [
    Transaction(
        version=1,
        locktime=0,
        timestamp=2,
        is_coinbase=True,
        fees=0,
        vin={0: TxIn(payout=None, sig="", pub_key=consts.WALLET_PUBLIC)},
        vout={
            0: TxOut(amount=5000000000, address=consts.WALLET_PUBLIC),
            1: TxOut(amount=4000000000, address=consts.WALLET_PUBLIC),
        },
    ),
    Transaction(
예제 #30
0

def fetch_peer_list():
    r = requests.get(consts.SEED_SERVER_URL)
    peer_list = json.loads(r.text)
    return peer_list


def get_peer_url(peer: Dict[str, Any]) -> str:
    return "http://" + str(peer["ip"]) + ":" + str(peer["port"])


if __name__ == "__main__":

    # The singleOutput for first coinbase transaction in genesis block
    so = SingleOutput(txid=dhash(first_block_transaction[0]), vout=0)

    first_transaction = Transaction(
        version=1,
        locktime=0,
        timestamp=3,
        is_coinbase=False,
        fees=4000000000,
        vin={0: TxIn(payout=so, sig="", pub_key=consts.WALLET_PUBLIC)},
        vout={0: TxOut(amount=1000000000, address=consts.WALLET_PUBLIC)}
    )

    sign_copy_of_tx = copy.deepcopy(first_transaction)
    sign_copy_of_tx.vin = {}
    w = Wallet()
    w.public_key = consts.WALLET_PUBLIC