Exemple #1
0
    def loadSys(self,sysIn):
        self.c_blockchainHandler.clearChainLoadGenesis()
        myUrl = m_info['nodeUrl']
        myNodeID = m_info['nodeId']
        m_info.clear()
        m_info.update(sysIn['m_info'])
        m_info["nodeUrl"] = myUrl
        m_info["nodeId"] = myNodeID
        m_cfg.clear()
        m_cfg.update(sysIn['m_cfg'])
        m_peerInfo.clear()
        m_peerInfo.update(sysIn['m_peerInfo'])
        m_Blocks.clear()
        for block in sysIn['m_Blocks']:
            if (len(m_Blocks) == 0):
                # TODO verify all fields are the same not only there!!!
                m, l, f = checkRequiredFields(block, m_genesisSet[0], [], False)
                if (len(m) == 0):
                    # TODO revert if loading failed!?!?!
                    m_Blocks.append(block)
                    continue
            else:
                ret = self.c_blockchainHandler.verifyThenAddBlock(block)
                if (len(ret) > 0):
                    # TODO revert if loading failed!?!?!
                    return errMsg(ret)

        m_pendingTX.update(sysIn['m_pendingTX'])
        m_BufferMinerCandidates.update(sysIn['m_BufferMinerCandidates'])
        m_stats.update(sysIn['m_stats'])
Exemple #2
0
def isDataValid(resp_text):
    m, l, f = checkRequiredFields(resp_text, m_candidateMiner, [], True)
    if (len(m) > 0) or (l != 0):
        d("required fields not matched")
        return False

    #TODO shoul dthis be further limited to half of zero and at least 5???
    if (resp_text['difficulty'] >= len(
            cfg['zero_string'])) or (resp_text['difficulty'] < 0):
        d("Difficulty not possible")
        return False

    if (resp_text['rewardAddress'] != cfg['address']) or (resp_text['index'] <=
                                                          0):
        d("Wrong reward address")
        return False

    if len(defHash) != len(resp_text['blockDataHash']):
        d("Wrong Hash length in blockDataHash" + resp_text['blockDataHash'])
        return False

    if resp_text['expectedReward'] < minBlockReward:
        d("Wrong Hash or too low expectedRewards: " +
          str(resp_text['expectedReward']))
        return False

    if resp_text['transactionsIncluded'] <= 0:
        d("No transaction at all")
        return False

    return True
Exemple #3
0
    def receivedBlockNotificationFromPeer(self, blockInfo):
        #TODO do we want to check if NodeUrl and real sender are identical??
        try:
            m, l, f = checkRequiredFields(blockInfo, m_informsPeerNewBlock, [], False)
            if (len(m) == 0) and (l == 0):
                return self.checkChainSituation('notification', blockInfo)
        except Exception:
            i=0

        return errMsg("Invalid block structure")
Exemple #4
0
    def getAllBlocksOneReadDirect(self):
        # coming here we are sure that we have back-up or nothing to loose!
        allPeersInfo = c_peer.sendGETToPeers("info")
        ret = -1

        while (ret != 200) and (len(allPeersInfo)>0):
            #some peers exists and may have blocks, so we follow them
            maxIdx = -1
            maxDiff = -1
            cnt = -1
            for detail, detail200 in allPeersInfo:
                cnt = cnt + 1
                if detail200 != 200:
                    #TODO actually should remove!!!!
                    continue
                m, l, f = checkRequiredFields(detail, m_info, [], False)
                if (isSameChain(detail) is True) and (len(m) == 0):
                    if maxDiff < detail['cumulativeDifficulty']:
                        maxDiff = detail['cumulativeDifficulty']
                        maxIdx = cnt
            if maxIdx >= 0:
                bestPeer = allPeersInfo[maxIdx][0]['nodeUrl']
                #bestPeer = bestPeer[0]
                #bestPeer = bestPeer['nodeUrl']
                blockList, ret = c_peer.sendGETToPeer(bestPeer+"/blocks")
                if ret == 200:
                    isFirst = True
                    for block in blockList:
                        if isFirst is True:
                            #TODO compare block with my genesis
                            # if any verification fails, set ret to -1
                            isFirst = False
                            m_info['cumulativeDifficulty'] = block['difficulty']
                            continue
                        if ret == 200:
                            if len(self.verifyThenAddBlock(block)) != 0:
                                self.clearChainLoadGenesis()
                                break
                        else:
                            self.clearChainLoadGenesis()
                            break
                    m_info['blocksCount'] = len(m_Blocks)
                    continue    # with ret being 200, this ends the loop!!!
                del allPeersInfo[maxIdx]
                continue
Exemple #5
0
    def getNextBlock(self, peer, offset):
        if (len(peer) > 0) and (peer[-1] != "/"):
            peer = peer + "/"
        base = "blocks/"
        url = base + str(len(m_Blocks)+offset)
        try:
            res, stat = c_peer.sendGETToPeer(peer + url)
        except Exception:
            d("peer failed" + peer)
            return "Block not available at " + peer, -1  # do not change it is checked outside

        if stat == 200:
            d("got peer block as requested with OK")
            m, l, f = checkRequiredFields(res, m_genesisSet[0], [], False)
            if len(m) == 0:
                if res['index'] == len(m_Blocks)+offset:
                    return res, stat
        return "Block not available/valid at " + peer, -1  # do not change it is checked outside
Exemple #6
0
    def suitablePeer(self, peer, fastTrack=False):
        try:
            s1 = self.doGET(peer + "/info", fastTrack)
            reply = json.loads(s1.text)
            m, l, f = checkRequiredFields(reply, m_info, ["chainId", "about"],
                                          False)
            if (len(f) > 0) or (
                    len(m) >
                    0):  # we skip to check any additional fields, is that OK
                print("Peer " + peer +
                      " reply not accepted, considered not alive")
                # as it is invalid peer, don't try again
                m_cfg['peers'][peer][
                    'wrongType'] = m_cfg['peers'][peer]['wrongType'] + 1
                del m_cfg['peers'][peer]
                m_info['peers'] = len(m_cfg['peers'])
                return {'wrongChain': True}

            if peer != reply['nodeUrl']:
                return {'Inconsistency in nodeURL': True}

            if not self.ensureBCNode(reply['type']):
                return {'wrongType': True}

            if isBCNode():
                if m_cfg['chainLoaded'] is True:
                    if (reply['blocksCount'] > len(m_Blocks)) or (
                            reply['blockHash'] != m_Blocks[-1]['blockHash']):
                        # ignore the return data from the situational check as here is primarily peer
                        # and informing the blockmanager about potential peers is secondary here
                        d("info showed longer block or different hash:" +
                          str(reply['blocksCount']) + " " +
                          str(len(m_Blocks)) + " " + reply['blockHash'] + " " +
                          m_Blocks[-1]['blockHash'])
                        project.classes.c_blockchainNode.c_blockchainHandler.checkChainSituation(
                            'info', reply)
                    if reply['blocksCount'] < len(m_Blocks):
                        # we found a laggard, let him know we are further
                        project.classes.c_blockchainNode.c_blockchainHandler.asynchNotifyPeers(
                        )
            return reply
        except Exception:
            return {'fail': True}
Exemple #7
0
    def peersConnect(self, source, values, isConnect):
        m, l, f = checkRequiredFields(['peerUrl'], values, [], False)
        if len(m) > 0:
            return errMsg("Missing field 'peerUrl' ")
        url = values['peerUrl']
        newURL = getValidURL(url, True)
        if newURL == "":
            return errMsg("Invalid URL: " + url)

        if isConnect:
            err = self.addPeerOption(url, source)
            if len(err) == 0:
                return setOK("Connection to peer registered")
            if err.startswith("Already connected"):
                return errMsg("Already connected to peer: " + url, 409)
        else:
            err = self.removePeerOption(url)
            if len(err) == 0:
                return setOK("Connection to peer removed")

        return errMsg(err)
Exemple #8
0
def verifyBlockAndAllTXOn(block, checkUnique):
    # make sure block has all fields and the correct chanId
    m, l, f = checkRequiredFields(block, m_completeBlock, ['chainId'], False)
    isGenesis = (block['index'] == 0)
    if isGenesis:
        # special case for genesis bloc
        if (len(m) != 1) or (m[0] != "prevBlockHash") or (l != -1) or (len(f) >
                                                                       0):
            return "Invalid Genesis block, should only not have 'prevBlockHash' but says " + str(
                m)
    else:
        if len(m) == 0:
            if block['prevBlockHash'] != m_Blocks[block["index"] -
                                                  1]['blockHash']:
                return "Block hash does not match previous block hash "
        else:
            return "Missing field(s): " + str(m)

        if (l != 0) or (len(f) > 0):
            return "Invalid block fields"

    #TODO check the hash of the blockhash!
    #blockHash = sha256ToHex(m_Miner_order, block) or use the update as we need to inlccude each TX below!!!

    isCoinBase = True  # Setting true here ensures that there is at least a coinbase there and not skipped
    for trans in block['transactions']:
        ret = verifyBasicTX(trans, isCoinBase, m_staticTransactionRef)
        #TODO add TX to block has!
        if (len(ret) > 0):
            return ret
        # we only ned to check block hashes as here we have no pending TXs
        if (checkUnique is True) and (isUniqueTXInBlocks(
                trans['transactionDataHash']) is False):
            return "Duplicate TX detected"
        isCoinBase = isGenesis  # genesis block verification only has coinbase like entries

    return ""
Exemple #9
0
    def nodeSpecificPOST(self, url, linkInfo, json, request):
        ret = {
            'NodeType': m_info['type'],
            'info': "This URL/API is not available/broken"
        }

        try:
            for x in json:
                if not re.match("[0-9a-zA-Z]+", x):
                    return errMsg("Invalid JSON key: " + str(x))
                if isinstance(json[x], str):
                    if not re.match("[0-9a-zA-Z \.%!@#$\-_+=;:,/?<>]*",
                                    json[x]):
                        return errMsg("Invalid character in JSON data: " +
                                      str(x))
                elif isinstance(json[x], list):
                    for xx in json[x]:
                        if isinstance(xx, str):
                            if not re.match("[0-9a-zA-Z \.%!@#$\-_+=;:,/?<>]*",
                                            xx):
                                return errMsg(
                                    "Invalid character in JSON data: " +
                                    str(xx))
                elif not isinstance(json[x], int):
                    return errMsg("Invalid character in JSON data: " +
                                  str(json[x]))

            # This is only applicable to POST, and is a shortcut to stop endless broadcast
            # of the same message
            for urlJson in m_peerSkip:
                if urlJson['url'] == url:
                    m, l, f = checkRequiredFields(json, urlJson['json'],
                                                  urlJson['json'], True)
                    if len(m) + len(f) == 0:
                        #TODO what text here?
                        return setOK("Acknowledge... ")
            # for bigger network, make this bigger as well?
            if len(m_peerSkip) > 10:
                del m_peerSkip[0]

            if self.permittedURLPOST(url) is False:
                return errMsg("This URL/API is invalid or not available. " +
                              url)

            d("Add delay url: '" + url + "' before we had " +
              str(len(m_isPOST)))
            m_isPOST.append(url)

            while (len(m_isPOST) > 1) or (m_cfg['chainInit'] is True):
                if self.delay(url, 2) is False:
                    break  # for some reason we decide to ignore the loop
            while len(m_simpleLock) > 0:
                if self.delay(url, 3) is False:
                    break  # for some reason we decide to ignore the loop

            self.release = False
            if isBCNode():
                ret = self.c_blockInterface.nodeSpecificPOSTNow(
                    url, linkInfo, json, request)
            elif isWallet():
                ret = self.c_walletInterface.nodeSpecificPOSTNow(
                    url, linkInfo, json, request)
            elif isFaucet():
                ret = self.c_faucetInterface.nodeSpecificPOSTNow(
                    url, linkInfo, json, request)
            elif isGenesis():
                ret = self.c_genesisInterface.nodeSpecificPOSTNow(
                    url, linkInfo, json, request)
        except Exception:
            d("*********************************************")
            d("*********************************************")
            print("POST exception caught, isPoststack " + str(len(m_isPOST)))
            d("*********************************************")
            d("*********************************************")

        if url in m_isPOST:
            m_isPOST.remove(url)
            d("Removed delay url: '" + url + "' back to " + str(len(m_isPOST)))
        self.release = True
        return ret
Exemple #10
0
def verifyBasicTX(trans, isCoinBase, ref):
    m, l, f = checkRequiredFields(trans, ref, [], False)
    colErr = ""
    for x in m:
        if colErr == "":
            colErr = "Missing field(s): '" + x + "'"
        else:
            colErr = colErr + "and '" + x + "'"
    # the entire check on the length has now been removed, because any addiitonal fields
    # within the TX are allowed, instead of being strict to follow only the exact specification,
    # such as to accept new forks which add new fields, but we do not accept missing fields
    # and by accepting addiiotnal fields, the check for unsuccessful is also not needed anymore
    # if l != 0:
    #     # only for cases of rejected TX we need to additionally check the two separate fields
    #     # if (l != 2):
    #     #     colErr = colErr + " Invalid number of fields in transaction: " + str(l) + str(trans)
    #     # else:
    #     #     if ("transferSuccessful" not in trans) or ("transactionDataHash" not in trans):
    #     #         colErr = colErr + " Problem with TX successfulField " + str(trans)
    #     #     else:
    #     #         l = 0  # not used so far, but prepare for any changes later
    #     # note we only check for known issues. If the TX has other more fields, so be it
    #     # because it could be from a fork
    #     # the only currently known issue is that more fields appear in unsuccessful TX, so this must be confirmed
    #     # a unsuccessful TX can have 2 or 3 more fields, depending the status it had when it was rejected
    #     # original version had only allowed 2 and did not consider the case that it could have been mined
    #     # and then the 'minedInBlock' also appears, so now we don't check length but just the two critical fields
    #     if isCoinBase is False:
    #         if 'transferSuccessful' in trans:
    #             if (trans['transferSuccessful'] is True) or ("transactionDataHash" not in trans):
    #                 colErr = colErr + "Problem with recognising TX as unsuccessful"

    if colErr == "":  # final checks
        if len(trans['senderSignature']) != 2:
            colErr = colErr + " Invalid number of elements in 'senderSignature' field"
        else:
            # len0 = len(trans['senderSignature'][0])
            # len1 = len(trans['senderSignature'][1])
            # len2 = len(defSig)
            if (len(trans['senderSignature'][0]) != len(trans['senderSignature'][1])) or\
                    (len(trans['senderSignature'][0]) != len(defSig)):
                colErr = colErr + " Invalid/Unpadded 'senderSignature' length"
            else:
                if isCoinBase:
                    if (trans['senderSignature'][0] !=
                            defSig) or (trans['senderSignature'][1] != defSig):
                        colErr = colErr + "Invalid senderSignature"
                else:
                    if (trans['senderSignature'][0]
                            == defSig) or (trans['senderSignature'][1]
                                           == defSig):
                        colErr = colErr + "Invalid senderSignature"
    if not isinstance(trans['fee'], int):
        colErr = colErr + "Fees must be integer, you sent: " + str(
            trans['fee'])
    else:
        if isCoinBase:
            if trans['fee'] != 0:
                colErr = colErr + "Coinbase fee should be zero, you sent: " + str(
                    trans['fee'])
        else:
            if trans['fee'] < m_stats['m_minFee']:
                colErr = colErr + "Minimun fee 10 micro-coins, you sent: " + str(
                    trans['fee'])
    if not isinstance(trans['value'], int):
        colErr = colErr + "Value must be integer, you sent: " + str(
            trans['value'])
    else:
        # slide 39 confirm that 0 value transactions are allowed
        if trans['value'] < 0:
            colErr = colErr + "Minimum value 0 micro-coins, you sent: " + str(
                trans['value'])
    if isCoinBase:
        # TODO any other coinbase checks
        colErr = colErr + verifyPubKey(trans['senderPubKey'], True)
        if trans['from'] != defAdr:
            colErr = colErr + "Invalid from in Coinbase"
    else:
        colErr = colErr + verifyAddr(trans['from'], trans['senderPubKey'])
    colErr = colErr + verifyAddr(trans['to'])

    if len(colErr) > 0:
        d("Verification problem: " + colErr)
    return colErr