Skip to content

Commit

Permalink
Merge pull request #111 from bridgedragon/feature/Method_getTransacti…
Browse files Browse the repository at this point in the history
…on_only_returns_in-wallet_transactions

Feature/method get transaction only returns in wallet transactions
  • Loading branch information
bridgedragon authored Mar 2, 2022
2 parents e076930 + b160596 commit d9971d7
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 100 deletions.
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"])
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

0 comments on commit d9971d7

Please sign in to comment.