Exemplo n.º 1
0
class OmniNode(object):

	def __init__(self, host, port, user, password):
		self.omniAccess = JsonRpcCaller(host, port, user, password)
		self.txProcessors = {
			0: self.processSimpleSend,
			3: self.processSendOwners,
			4: self.processSendAll,
			20: self.processSellForBitcoin,
			22: self.processAcceptSellForBitcoin,
			50: self.processCreateFixedProperty,
			51: self.processCreateCrowdsaleProperty,
			53: self.processCloseCrowdsale,
			54: self.processCreateManagedProperty,
			55: self.processGrantTokens,
			56: self.processRevokeTokens,
		}

	def getBlockCount(self):
		return self.omniAccess.call("getblockcount")

	def getBlock(self, height):
		blockHash = self.omniAccess.call("getblockhash", [height])
		blockDict = self.omniAccess.call("getblock", [blockHash])
		hashAsNumber = int(blockDict["hash"], base=16)
		assert(hashAsNumber < 10**HASH_PRECISION)
		block = OmniBlockData(height, hashAsNumber, datetime.utcfromtimestamp(blockDict["time"]))

		transactionHashes = self.omniAccess.call("omni_listblocktransactions", [height])
		# no bulk request due to Omni node freezing
		for txHash in transactionHashes:
			txInfo = self.omniAccess.call("omni_gettransaction", [txHash])
			if not "valid" in txInfo:
				assert(txInfo["type"] == "DEx Purchase")
				self.processDexPurchase(txInfo, block)
			elif txInfo["valid"]:
				txType = txInfo["type_int"]
				if txType in self.txProcessors:
					self.txProcessors[txType](txInfo, block)
				elif txType not in IGNORE_TX_TYPES:
					print txInfo
					print "unknown tx type: {0}".format(txType)
					assert(False)
				

		return block

	def processSimpleSend(self, txInfo, block):
		assert(len(txInfo["referenceaddress"]) < MAX_ADDRESS_LENGTH)
		txHash, txTime, sendingAddress, propertyId, fee = self.getCommonTxAttributes(txInfo)
		txData = OmniSimpleSendTransaction(block.blockHash, txHash, txTime, propertyId, sendingAddress, 
			txInfo["referenceaddress"], omniOutputValueSatoshi(txInfo["amount"]), fee)
		block.addSimpleSendTransaction(txData)

	def processSendAll(self, txInfo, block):
		assert(len(txInfo["referenceaddress"]) < MAX_ADDRESS_LENGTH)
		assert(len(txInfo["sendingaddress"]) < MAX_ADDRESS_LENGTH)
		hashAsNumber = int(txInfo["txid"], base=16)
		assert(hashAsNumber < 10**HASH_PRECISION)
		txTime = datetime.utcfromtimestamp(txInfo["blocktime"])
		for index, send in enumerate(txInfo["subsends"]):
			txData = OmniSendAllTransaction(block.blockHash, hashAsNumber, index, txTime, send["propertyid"], 
				txInfo["sendingaddress"], txInfo["referenceaddress"], omniOutputValueSatoshi(send["amount"]),
				omniOutputValueSatoshi(txInfo["fee"]))
			block.addSendAllTransaction(txData)

	def processSendOwners(self, txInfo, block):
		txHash, txTime, sendingAddress, propertyId, fee = self.getCommonTxAttributes(txInfo)
		txData = OmniSendOwnersTransaction(block.blockHash, txHash, txTime, propertyId, sendingAddress, 
			omniOutputValueSatoshi(txInfo["amount"]), fee)
		block.addSendOwnersTransaction(txData)

	def processSellForBitcoin(self, txInfo, block):
		if not txInfo["action"] in SELL_FOR_BITCOIN_ACTIONS:
			print txInfo
			print "unknown action of sell-for-bitcoin tx: {0}".format(txInfo["action"])
			assert(False)
		txHash, txTime, sendingAddress, propertyId, fee = self.getCommonTxAttributes(txInfo)
		txData = OmniSellForBitcoinTransaction(block.blockHash, txHash, txTime, propertyId, sendingAddress, 
			omniOutputValueSatoshi(txInfo["amount"]), fee, omniOutputValueSatoshi(txInfo["feerequired"]),
			omniOutputValueSatoshi(txInfo["bitcoindesired"]), SELL_FOR_BITCOIN_ACTIONS[txInfo["action"]])
		block.addSellForBitcoinTransaction(txData)

	def processAcceptSellForBitcoin(self, txInfo, block):
		assert(len(txInfo["referenceaddress"]) < MAX_ADDRESS_LENGTH)
		txHash, txTime, sendingAddress, propertyId, fee = self.getCommonTxAttributes(txInfo)
		txData = OmniAcceptSellForBitcoinTransaction(block.blockHash, txHash, txTime, propertyId, sendingAddress, 
			omniOutputValueSatoshi(txInfo["amount"]), fee, txInfo["referenceaddress"])
		block.addAcceptSellForBitcoinTransaction(txData)

	def processCreateFixedProperty(self, txInfo, block):
		if not txInfo["propertytype"] in PROPERTY_TYPES:
			print txInfo
			print "unknown property type: {0}".format(txInfo["propertytype"])
			assert(False)
		txHash, txTime, sendingAddress, propertyId, fee = self.getCommonTxAttributes(txInfo)
		txData = OmniCreateFixedPropertyTransaction(block.blockHash, txHash, txTime, propertyId, sendingAddress, 
			omniOutputValueSatoshi(txInfo["amount"]), fee, PROPERTY_TYPES[txInfo["propertytype"]])
		block.addCreateFixedPropertyTransaction(txData)

	def processCreateManagedProperty(self, txInfo, block):
		if not txInfo["propertytype"] in PROPERTY_TYPES:
			print txInfo
			print "unknown property type: {0}".format(txInfo["propertytype"])
			assert(False)
		txHash, txTime, sendingAddress, propertyId, fee = self.getCommonTxAttributes(txInfo)
		txData = OmniCreateManagedPropertyTransaction(block.blockHash, txHash, txTime, propertyId, sendingAddress, 
			fee, PROPERTY_TYPES[txInfo["propertytype"]])
		block.addCreateManagedPropertyTransaction(txData)

	def processGrantTokens(self, txInfo, block):
		assert(len(txInfo["referenceaddress"]) < MAX_ADDRESS_LENGTH)
		txHash, txTime, sendingAddress, propertyId, fee = self.getCommonTxAttributes(txInfo)
		txData = OmniGrantTokensTransaction(block.blockHash, txHash, txTime, propertyId, sendingAddress, 
			txInfo["referenceaddress"], omniOutputValueSatoshi(txInfo["amount"]), fee)
		block.addGrantTokensTransaction(txData)

	def processRevokeTokens(self, txInfo, block):
		txHash, txTime, sendingAddress, propertyId, fee = self.getCommonTxAttributes(txInfo)
		txData = OmniRevokeTokensTransaction(block.blockHash, txHash, txTime, propertyId, sendingAddress, 
			omniOutputValueSatoshi(txInfo["amount"]), fee)
		block.addRevokeTokensTransaction(txData)

	def processCreateCrowdsaleProperty(self, txInfo, block):
		if not txInfo["propertytype"] in PROPERTY_TYPES:
			print txInfo
			print "unknown property type: {0}".format(txInfo["propertytype"])
			assert(False)
		try:
			deadline = datetime.utcfromtimestamp(txInfo["deadline"])
		except ValueError:
			deadline = datetime(2100, 1, 1)
		txHash, txTime, sendingAddress, propertyId, fee = self.getCommonTxAttributes(txInfo)
		txData = OmniCreateCrowdsalePropertyTransaction(block.blockHash, txHash, txTime, propertyId, sendingAddress, omniOutputValueSatoshi(txInfo["amount"]), 
			fee, PROPERTY_TYPES[txInfo["propertytype"]], omniOutputValueSatoshi(txInfo["tokensperunit"]), 
			deadline, txInfo["earlybonus"], txInfo["percenttoissuer"])
		block.addCreateCrowdsalePropertyTransaction(txData)

	def processCloseCrowdsale(self, txInfo, block):
		txHash, txTime, sendingAddress, propertyId, fee = self.getCommonTxAttributes(txInfo)
		txData = OmniTransactionBase(block.blockHash, txHash, txTime, propertyId, sendingAddress, fee)
		block.addCloseCrowdsaleTransaction(txData)		

	def processDexPurchase(self, txInfo, block):
		assert(len(txInfo["sendingaddress"]) < MAX_ADDRESS_LENGTH)
		hashAsNumber = int(txInfo["txid"], base=16)
		assert(hashAsNumber < 10**HASH_PRECISION)
		txTime = datetime.utcfromtimestamp(txInfo["blocktime"])
		for index, purchase in enumerate(txInfo["purchases"]):
			if purchase["valid"]:
				assert(len(purchase["referenceaddress"]) < MAX_ADDRESS_LENGTH)
				txData = OmniDexPurchaseTransaction(block.blockHash, hashAsNumber, index, txTime, purchase["propertyid"], 
					txInfo["sendingaddress"], purchase["referenceaddress"], omniOutputValueSatoshi(purchase["amountbought"]), 
					omniOutputValueSatoshi(purchase["amountpaid"]))
				block.addDexPurchaseTransaction(txData)

	def getCommonTxAttributes(self, txInfo):
		assert(len(txInfo["sendingaddress"]) < MAX_ADDRESS_LENGTH)
		hashAsNumber = int(txInfo["txid"], base=16)
		assert(hashAsNumber < 10**HASH_PRECISION)
		txTime = datetime.utcfromtimestamp(txInfo["blocktime"])
		return hashAsNumber, txTime, txInfo["sendingaddress"], txInfo["propertyid"], omniOutputValueSatoshi(txInfo["fee"])

	
		
Exemplo n.º 2
0
class BitcoinNodeBase(object):
    def __init__(self, host, port, user, password):
        self.bitcoinAccess = JsonRpcCaller(host, port, user, password)

    def getBlockCount(self):
        return self.bitcoinAccess.call("getblockcount")

    def getBlock(self, height):
        blockHash = self.bitcoinAccess.call("getblockhash", [height])
        blockDict = self.bitcoinAccess.call("getblock", [blockHash])
        block = self.initBlock(blockDict)

        txDicts = self.getBlockTransactions(blockDict, block)
        txIndex = 0
        for txDict in txDicts:
            transaction = self.processTransaction(txDict, txIndex, block)
            block.addTransaction(transaction)
            txIndex += 1

        return block

    def getBlockTransactions(self, blockDict, blockData):
        hashes = []
        for txHash in blockDict["tx"]:
            if not self.excludeTransaction(txHash, blockData):
                hashes.append(txHash)
        if len(hashes) > 0:
            return self.bitcoinAccess.bulkCall(
                ("getrawtransaction", [txHash, 1]) for txHash in hashes)
        else:
            return []

    def initBlock(self, blockDict):
        hashAsNumber = int(blockDict["hash"], base=16)
        assert (hashAsNumber < 10**HASH_PRECISION)
        chainWorkAsNumber = self.getBlockChainWork(blockDict)
        assert (chainWorkAsNumber < 10**CHAINWORK_PRECISION)
        blockTime = datetime.utcfromtimestamp(blockDict["time"])
        blockSize = int(blockDict["size"])
        difficulty = float(blockDict["difficulty"])
        height = int(blockDict["height"])
        return BitcoinBlockData(height, hashAsNumber, chainWorkAsNumber,
                                blockTime, blockSize, difficulty)

    def getBlockChainWork(self, blockDict):
        return int(blockDict["chainwork"], base=16)

    def processTransaction(self, txDict, txIndex, blockData):
        transaction = self.initTransaction(txDict, txIndex, blockData)
        self.processInputs(transaction, txDict, txIndex)
        self.processOutputs(transaction, txDict, txIndex)
        return transaction

    def initTransaction(self, txDict, txIndex, blockData):
        txSize = self.getTransactionSize(txDict)
        txHashAsNumber = int(txDict["txid"], base=16)
        assert (txHashAsNumber < 10**HASH_PRECISION)
        coinbase = self.transactionIsCoinbase(txDict, txIndex, blockData)
        return BitcoinTransactionData(txHashAsNumber, txSize,
                                      blockData.blockTime, coinbase)

    def getTransactionSize(self, txDict):
        return int(txDict["size"])

    def transactionIsCoinbase(self, txDict, txIndex, blockData):
        for inputDict in txDict["vin"]:
            if "coinbase" in inputDict:
                return True
        return False

    def excludeTransaction(self, txHash, blockData):
        return False

    def processInputs(self, transaction, txDict, txIndex):
        if self.shouldProcessTxInputs(transaction, txDict, txIndex):
            index = 0
            for inputDict in txDict["vin"]:
                self.processInput(transaction, inputDict, index)
                index += 1

    def shouldProcessTxInputs(self, transaction, txDict, txIndex):
        return not transaction.coinbase

    def processInput(self, transaction, inputDict, inputIndex):
        inputTxHashAsNumber = int(inputDict["txid"], base=16)
        outputIndex = int(inputDict["vout"])
        transaction.addInput((inputTxHashAsNumber, outputIndex))

    def processOutputs(self, transaction, txDict, txIndex):
        outputIndex = 0
        for outputDict in txDict["vout"]:
            self.processOutput(transaction, outputDict, outputIndex)
            outputIndex += 1

    def processOutput(self, transaction, outputDict, outputIndex):
        if not outputDict["scriptPubKey"]["type"] in OUTPUT_TYPES:
            print outputDict["scriptPubKey"]["type"]
        assert (outputDict["scriptPubKey"]["type"] in OUTPUT_TYPES)
        outputType = OUTPUT_TYPES[outputDict["scriptPubKey"]["type"]]

        if "addresses" in outputDict["scriptPubKey"]:
            addresses = outputDict["scriptPubKey"]["addresses"]
            for address in addresses:
                assert (len(address) <= MAX_ADDRESS_LENGTH)
                assert (len(address) > 0)
        else:
            addresses = []

        if outputType in [
                OUTPUT_TYPES["nonstandard"], OUTPUT_TYPES["nulldata"],
                OUTPUT_TYPES["multisig"]
        ]:
            pass
        elif outputType == OUTPUT_TYPES["pubkey"]:
            if "addresses" in outputDict["scriptPubKey"]:
                assert (len(addresses) == 1)
        elif outputType in [
                OUTPUT_TYPES["witness_v0_keyhash"],
                OUTPUT_TYPES["witness_v0_scripthash"]
        ]:
            assert (len(addresses) <= 1)
            if len(addresses) == 0:
                prefix = "wkh_" if outputType == OUTPUT_TYPES[
                    "witness_v0_keyhash"] else "wsh_"
                addresses = [
                    bech32.encode(prefix, 0, [
                        ord(s) for s in binascii.unhexlify(
                            outputDict["scriptPubKey"]["hex"][4:])
                    ])
                ]
        else:
            assert (len(addresses) == 1)

        scriptHex = outputDict["scriptPubKey"]["hex"]
        value = outputValueToSatoshis(outputDict["value"])
        transaction.addOutput(
            (outputIndex, outputType, addresses, scriptHex, value))