Skip to content

Feature/method get transaction only returns in wallet transactions #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

62 changes: 28 additions & 34 deletions Connector/btc/apirpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from logger import logger
from rpcutils import error
from rpcutils.rpcconnector import RPCConnector
from rpcutils.rpcsocketconnector import RPCSocketConnector
from . import utils
from .constants import *

Expand Down Expand Up @@ -367,7 +368,7 @@ def getTransactionHex(id, params, config):
rawTransaction = RPCConnector.request(
endpoint=config.bitcoincoreRpcEndpoint,
id=id,
method=GET_TRANSACTION_METHOD,
method=GET_RAW_TRANSACTION_METHOD,
params=[params["txHash"]]
)

Expand All @@ -383,7 +384,6 @@ def getTransactionHex(id, params, config):
@rpcmethod.rpcMethod(coin=COIN_SYMBOL)
@httpmethod.postHttpMethod(coin=COIN_SYMBOL)
def getTransaction(id, params, config):

logger.printInfo(f"Executing RPC method getTransaction with id {id} and params {params}")

requestSchema, responseSchema = utils.getMethodSchemas(GET_TRANSACTION)
Expand All @@ -393,53 +393,47 @@ def getTransaction(id, params, config):
raise error.RpcBadRequestError(err.message)

try:
# Parameters: TransactionId, include_watchonly, verbose
transaction = RPCConnector.request(
endpoint=config.bitcoincoreRpcEndpoint,
id=id,
method=GET_TRANSACTION_METHOD,
method=GET_RAW_TRANSACTION_METHOD,
params=[
params["txHash"],
True,
True
]
)

vinAddressBalances = {}
transactionAmount = 0
# Check if transaction is confirmed, and obtain block number
if "blockhash" in transaction:
transactionBlock = RPCConnector.request(
endpoint=config.bitcoincoreRpcEndpoint,
id=id,
method=GET_BLOCK,
params=[transaction["blockhash"], 1]
)
blockNumber = transactionBlock["height"]
else:
blockNumber = None

if "generated" not in transaction:

for vin in transaction["decoded"]["vin"]:
inputTransaction = RPCConnector.request(
endpoint=config.bitcoincoreRpcEndpoint,
id=id,
method=GET_TRANSACTION_METHOD,
params=[
vin["txid"],
True,
True
]
)
transactionDetails = utils.decodeTransactionDetails(transaction, config.bitcoincoreRpcEndpoint)

transactionAmount += inputTransaction["decoded"]["vout"][vin["vout"]]["value"]
address = inputTransaction["decoded"]["vout"][vin["vout"]]["scriptPubKey"]["addresses"][0]
value = inputTransaction["decoded"]["vout"][vin["vout"]]["value"]
vinAddressBalances[address] = value
# Converting all transaction details to str
transactionDetails["fee"] = str(transactionDetails["fee"])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to store the string value, just return the string value in response variable, "fee":str(transactionDetails["fee"])

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree with this, because we are converting all elements in the array at once. I do not want to mix str variables with not-str ones in the same array.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is that the behaviour is the same if you delete this line and add "fee":str(transactionDetails["fee"]) in line 434

for input in transactionDetails["inputs"]:
input["amount"] = str(input["amount"])
for output in transactionDetails["outputs"]:
output["amount"] = str(output["amount"])

response = {
"transaction": {
"txHash": params["txHash"],
"blockhash": transaction["blockhash"] if transaction["confirmations"] >= 1 else None,
"blockNumber": str(transaction["blockheight"]) if transaction["confirmations"] >= 1 else None,
"fee": str(utils.convertToSatoshi(-transaction["fee"])) if "generated" not in transaction else "0",
"transfers": utils.parseBalancesToTransfers(
vinAddressBalances,
transaction["details"],
-transaction["fee"] if "generated" not in transaction else 0,
transactionAmount
),
"data": transaction["decoded"]
"txId": transaction["txid"],
"txHash": transaction["hash"],
"blockNumber": str(blockNumber) if blockNumber is not None else blockNumber,
"fee": transactionDetails["fee"],
"inputs": transactionDetails["inputs"],
"outputs": transactionDetails["outputs"],
"data": transaction
}
}

Expand Down
24 changes: 23 additions & 1 deletion Connector/btc/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ def __init__(self, coin, networkName):
self._electrumPassword = ""
self._bitcoincoreCallbackProtocol = ""
self._bitcoincoreCallbackHost = ""
self._electrumxHost = ""
self._electrumxPort = 0

def loadConfig(self, config):

Expand Down Expand Up @@ -57,6 +59,8 @@ def loadConfig(self, config):
else defaultConfig["bitcoincoreCallbackProtocol"]
self.bitcoincoreCallbackHost = config["bitcoincoreCallbackHost"] if "bitcoincoreCallbackHost" in config \
else defaultConfig["bitcoincoreCallbackHost"]
self.electrumxHost = config["electrumxHost"] if "electrumxHost" in config else defaultConfig["electrumxHost"]
self.electrumxPort = config["electrumxPort"] if "electrumxPort" in config else defaultConfig["electrumxPort"]

return True, None

Expand Down Expand Up @@ -184,6 +188,22 @@ def bitcoincoreCallbackHost(self):
def bitcoincoreCallbackHost(self, value):
self._bitcoincoreCallbackHost = value

@property
def electrumxHost(self):
return self._electrumxHost

@electrumxHost.setter
def electrumxHost(self, value):
self._electrumxHost = value

@property
def electrumxPort(self):
return self._electrumxPort

@electrumxPort.setter
def electrumxPort(self, value):
self._electrumxPort = value

@property
def bitcoincoreRpcEndpoint(self):
return f"{self.bitcoincoreProtocol}://" \
Expand Down Expand Up @@ -226,5 +246,7 @@ def encode(self, o):
"electrumHost": o.electrumHost,
"electrumPort": o.electrumPort,
"electrumUser": o.electrumUser,
"electrumPassword": o.electrumPassword
"electrumPassword": o.electrumPassword,
"electrumxHost": o.electrumxHost,
"electrumxPort": o.electrumxPort
}
3 changes: 2 additions & 1 deletion Connector/btc/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
GET_BLOCK_HASH_METHOD = "getblockhash"
GET_BLOCK_COUNT_METHOD = "getblockcount"
ESTIMATE_SMART_FEE_METHOD = "estimatesmartfee"
GET_TRANSACTION_METHOD = "gettransaction"
GET_RAW_TRANSACTION_METHOD = "getrawtransaction"
DECODE_RAW_TRANSACTION_METHOD = "decoderawtransaction"
SEND_RAW_TRANSACTION_METHOD = "sendrawtransaction"
NOTIFY_METHOD = "notify"
Expand Down Expand Up @@ -100,6 +100,7 @@
NOTIFY = "notify"
NEW_HASH_BLOCK_ZMQ_TOPIC = "hashblock"
NEW_RAW_BLOCK_ZMQ_TOPIC = "rawblock"
GET_BLOCK = "getblock"

SUBSCRIBE_ADDRESS_BALANCE = "subscribetoaddressbalance"
UNSUBSCRIBE_ADDRESS_BALANCE = "unsubscribefromaddressbalance"
Expand Down
4 changes: 3 additions & 1 deletion Connector/btc/defaultConf.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@
"electrumUser": "swapper",
"electrumPassword": "swapper",
"bitcoincoreCallbackProtocol": "http",
"bitcoincoreCallbackHost": "connector"
"bitcoincoreCallbackHost": "connector",
"electrumxHost": "electrs",
"electrumxPort": 60001
}
27 changes: 20 additions & 7 deletions Connector/btc/rpcschemas/gettransaction_response.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,31 @@
"fee": {
"type": "string"
},
"transfers": {
"inputs": {
"type": "array",
"items": {
"properties": {
"from": {
"type": "string"
},
"to": {
"type": "string"
"address": {
"type": [
"string",
"null"
]
},
"fee": {
"amount": {
"type": "string"
}
}
}
},
"outputs": {
"type": "array",
"items": {
"properties": {
"address": {
"type": [
"string",
"null"
]
},
"amount": {
"type": "string"
Expand Down
95 changes: 52 additions & 43 deletions Connector/btc/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
#!/usr/bin/python3
import binascii
import hashlib
import math
from decimal import Decimal
import random
import sys
from logger import logger
from rpcutils import error as rpcerrorhandler
from wsutils import topics
from rpcutils.rpcconnector import RPCConnector
from rpcutils.rpcsocketconnector import RPCSocketConnector
from .constants import *
from . import apirpc

Expand Down Expand Up @@ -64,49 +69,53 @@ def closeAddrBalanceTopic(topicName):
raise rpcerrorhandler.BadRequestError(f"Can not unsubscribe {topicName} to node")


def parseBalancesToTransfers(vin, vout, fee, amount):

transfers = []
diff = 0

for utxo in vout:

if utxo["category"] == "send":

for address in list(vin.keys()):

voutAmount = -utxo["amount"]
vinAmount = vin[address]

if vinAmount <= (voutAmount + diff):
transfer = {
"from": address,
"to": utxo["address"],
"amount": str(convertToSatoshi(vinAmount)),
"fee": str(convertToSatoshi(round(vinAmount * fee / amount, BTC_PRECISION)))
}
del vin[address]
else:
transfer = {
"from": address,
"to": utxo["address"],
"amount": str(convertToSatoshi(voutAmount)),
"fee": str(convertToSatoshi(round(voutAmount * fee / amount, BTC_PRECISION)))
}

diff = diff + voutAmount - vinAmount
transfers.append(transfer)

if utxo["category"] in ["generate", "immature", "orphan"]:
transfers.append(
{
"to": utxo["address"],
"fee": "0",
"amount": str(convertToSatoshi(utxo["maount"]))
}
)

return transfers
def decodeTransactionDetails(txDecoded, bitcoincoreRpcEndpoint):
outputs = []
for output in txDecoded["vout"]:
if "addresses" in output["scriptPubKey"] and len(output["scriptPubKey"]["addresses"]) == 1:
outputs.append(
{"amount": math.trunc(output["value"] * 100000000), "address": output["scriptPubKey"]["addresses"][0]})
else:
outputs.append({"amount": math.trunc(output["value"] * 100000000), "address": None})

sumOutputs = 0
for output in outputs:
sumOutputs += output["amount"]

inputs = []
for txInput in txDecoded["vin"]:

if "coinbase" in txInput: # This is a coinbase transaction and thus it have one only input of 'sumOutputs'
inputs.append({"amount": sumOutputs, "address": None})
break

transaction = RPCConnector.request(
endpoint=bitcoincoreRpcEndpoint,
id=0,
method="getrawtransaction",
params=[
txInput["txid"],
True
]
)

for txOutput in transaction["vout"]:
if txOutput["n"] == txInput["vout"] and "addresses" in txOutput["scriptPubKey"] and len(
txOutput["scriptPubKey"]["addresses"]) == 1:
inputs.append({"amount": math.trunc(txOutput["value"] * 100000000),
"address": txOutput["scriptPubKey"]["addresses"][0]})
elif "addresses" not in txOutput["scriptPubKey"] or len(txOutput["scriptPubKey"]["addresses"]) != 1:
inputs.append({"amount": math.trunc(txOutput["value"] * 100000000), "address": None})

sumInputs = 0
for txInput in inputs:
sumInputs += txInput["amount"]

fee = sumInputs - sumOutputs

transactionsDetails = {"fee": fee, "inputs": inputs, "outputs": outputs}

return transactionsDetails


def sortUnspentOutputs(outputs):
Expand Down
14 changes: 9 additions & 5 deletions Connector/eth/apirpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,16 @@ def getTransaction(id, params, config):
"blockHash": transaction["blockHash"],
"blockNumber": str(int(transaction["blockNumber"], 16)) if transaction["blockNumber"] is not None else None,
"data": transaction,
"transfers": [
"inputs": [
{
"from": transaction["from"],
"to": transaction["to"],
"amount": str(utils.toWei(transaction["value"])),
"fee": str(utils.toWei(transaction["gasPrice"]) * utils.toWei(transaction["gas"]))
"address": transaction["from"],
"amount": str(utils.toWei(transaction["value"]))
}
],
"outputs": [
{
"address": transaction["to"],
"amount": str(utils.toWei(transaction["value"]))
}
]
}
Expand Down
26 changes: 18 additions & 8 deletions Connector/eth/rpcschemas/gettransaction_response.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,31 @@
"fee": {
"type": "string"
},
"transfers": {
"inputs": {
"type": "array",
"items": {
"type": "object",
"properties": {
"from": {
"type": "string"
},
"to": {
"type": "string"
"address": {
"type": [
"string"
]
},
"amount": {
"type": "string"
}
}
}
},
"outputs": {
"type": "array",
"items": {
"properties": {
"address": {
"type": [
"string"
]
},
"fee": {
"amount": {
"type": "string"
}
}
Expand Down
Loading