Skip to content

39 Implement endpoints for XMR API #41

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

Draft
wants to merge 9 commits into
base: staging
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Connector/config.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"version": "1.1.6"
"version": "1.1.8"
}
259 changes: 254 additions & 5 deletions Connector/xmr/apirpc.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,263 @@
from httputils import httputils
from .constants import *
from .connector import RPC_ENDPOINT
from .connector import RPC_MONEROD_ENDPOINT, RPC_WALLET_ENDPOINT, WALLET_NAME, WALLET_PASSWORD
from rpcutils import rpcutils, errorhandler as rpcerrorhandler
from rpcutils.rpcconnector import RPCConnector
from . import utils
from logger import logger


@httputils.getMethod
@rpcutils.rpcMethod
def syncing(id, params):
def getFeePerByte(id, params):
logger.printInfo(f"Executing RPC method getFeePerByte with id {id} and params {params}")

requestSchema, responseSchema = utils.getMethodSchemas(GET_FEE_PER_BYTE)

err = rpcutils.validateJSONRPCSchema(params, requestSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

fee = RPCConnector.request(RPC_MONEROD_ENDPOINT, id, GET_FEE_ESTIMATE_METHOD, None)

if fee is None:
logger.printWarning("Could not get fee info from node")
raise rpcerrorhandler.BadRequestError("Could not get fee info from node")

response = {
FEE_PER_BYTE: fee[FEE]
}

err = rpcutils.validateJSONRPCSchema(response, responseSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

return response


@httputils.postMethod
@rpcutils.rpcMethod
def getBlockByNumber(id, params):
logger.printInfo(f"Executing RPC method getBlockByNumber with id {id} and params {params}")

requestSchema, responseSchema = utils.getMethodSchemas(GET_BLOCK_BY_NUMBER)

err = rpcutils.validateJSONRPCSchema(params, requestSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

try:
blockNumber = int(params[BLOCK_NUMBER], base=10)
except Exception as err:
raise rpcerrorhandler.BadRequestError(str(err))

block = RPCConnector.request(RPC_MONEROD_ENDPOINT, id, GET_BLOCK_METHOD, [blockNumber])

if block is None:
logger.printWarning("Could not get block info from node")
raise rpcerrorhandler.BadRequestError("Could not get block info from node")

err = rpcutils.validateJSONRPCSchema(block, responseSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

return block


@httputils.postMethod
@rpcutils.rpcMethod
def getBlockByHash(id, params):
logger.printInfo(f"Executing RPC method getBlockByHash with id {id} and params {params}")

requestSchema, responseSchema = utils.getMethodSchemas(GET_BLOCK_BY_HASH)

err = rpcutils.validateJSONRPCSchema(params, requestSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

block = RPCConnector.request(RPC_MONEROD_ENDPOINT, id, GET_BLOCK_METHOD, [params[BLOCK_HASH]])

if block is None:
logger.printWarning("Could not get block info from node")
raise rpcerrorhandler.BadRequestError("Could not get block info from node")

err = rpcutils.validateJSONRPCSchema(block, responseSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

return block


@httputils.getMethod
@rpcutils.rpcMethod
def getHeight(id, params):
logger.printInfo(f"Executing RPC method getHeight with id {id} and params {params}")

requestSchema, responseSchema = utils.getMethodSchemas(GET_HEIGHT)

err = rpcutils.validateJSONRPCSchema(params, requestSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

blockchainInfo = RPCConnector.request(RPC_MONEROD_ENDPOINT, id, GET_INFO_METHOD, None)

if blockchainInfo is None:
logger.printWarning("Could not get latest blockchain info from node")
raise rpcerrorhandler.BadRequestError("Could not get latest blockchain info from node")

response = {
LATEST_BLOCK_INDEX: blockchainInfo[HEIGHT],
LATEST_BLOCK_HASH: blockchainInfo[TOP_BLOCK_HASH]
}

err = rpcutils.validateJSONRPCSchema(response, responseSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

return response


@httputils.postMethod
@rpcutils.rpcMethod
def getTxProof(id, params):
logger.printInfo(f"Executing RPC method getTxProof with id {id} and params {params}")

requestSchema, responseSchema = utils.getMethodSchemas(GET_TX_PROOF)

err = rpcutils.validateJSONRPCSchema(params, requestSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

logger.printInfo(f"Trying to open the wallet {WALLET_NAME}")
RPCConnector.request(RPC_WALLET_ENDPOINT, id, OPEN_WALLET_METHOD, WALLET_NAME, WALLET_PASSWORD)

sign = RPCConnector.request(RPC_WALLET_ENDPOINT, id, GET_TX_PROOF_METHOD, [params[TX_ID], params[ADDRESS], params[MESSAGE]])

if sign is None:
logger.printWarning(f"Could not get any signature from transaction id {params[TX_ID]}")
raise rpcerrorhandler.BadRequestError(f"Could not get any signature from transaction id {params[TX_ID]}")

response = {
SIGNATURE: sign[SIGNATURE]
}

err = rpcutils.validateJSONRPCSchema(response, responseSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

return response


@httputils.postMethod
@rpcutils.rpcMethod
def checkTxProof(id, params):
logger.printInfo(f"Executing RPC method checkTxProof with id {id} and params {params}")

requestSchema, responseSchema = utils.getMethodSchemas(CHECK_TX_PROOF)

err = rpcutils.validateJSONRPCSchema(params, requestSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

logger.printInfo(f"Trying to open the wallet {WALLET_NAME}")
RPCConnector.request(RPC_WALLET_ENDPOINT, id, OPEN_WALLET_METHOD, WALLET_NAME, WALLET_PASSWORD)

txProof = RPCConnector.request(RPC_WALLET_ENDPOINT, id, CHECK_TX_PROOF_METHOD, [params[TX_ID], params[ADDRESS], params[MESSAGE], params[SIGNATURE]])

if txProof is None:
logger.printWarning("Could not get any transaction proof info from node")
raise rpcerrorhandler.BadRequestError("Could not get any transaction proof info from node")

if txProof[PROVEN] == "false":
logger.printWarning(f"Transaction {txProof[TX_ID]} can't be proven")
response = {
PROVEN: False
}

response = {
CONFIRMATIONS: txProof[CONFIRMATIONS],
PROVEN: True,
AMOUNT: txProof[RECEIVED]
}

err = rpcutils.validateJSONRPCSchema(response, responseSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

return response


@httputils.postMethod
@rpcutils.rpcMethod
def getSpendProof(id, params):
logger.printInfo(f"Executing RPC method getSpendProof with id {id} and params {params}")

requestSchema, responseSchema = utils.getMethodSchemas(GET_SPEND_PROOF)

err = rpcutils.validateJSONRPCSchema(params, requestSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

logger.printInfo(f"Trying to open the wallet {WALLET_NAME}")
RPCConnector.request(RPC_WALLET_ENDPOINT, id, OPEN_WALLET_METHOD, WALLET_NAME, WALLET_PASSWORD)

sign = RPCConnector.request(RPC_WALLET_ENDPOINT, id, GET_SPEND_PROOF_METHOD, [params[TX_ID], params[MESSAGE]])

if sign is None:
logger.printWarning(f"Could not generate any signature from transaction id {params[TX_ID]} to proof the spend")
raise rpcerrorhandler.BadRequestError(f"Could not generate any signature from transaction id {params[TX_ID]} to proof the spend")

response = {
SIGNATURE: sign[SIGNATURE]
}

err = rpcutils.validateJSONRPCSchema(response, responseSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

return response


@httputils.postMethod
@rpcutils.rpcMethod
def checkSpendProof(id, params):
logger.printInfo(f"Executing RPC method checkSpendProof with id {id} and params {params}")

requestSchema, responseSchema = utils.getMethodSchemas(CHECK_SPEND_PROOF)

err = rpcutils.validateJSONRPCSchema(params, requestSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

logger.printInfo(f"Trying to open the wallet {WALLET_NAME}")
RPCConnector.request(RPC_WALLET_ENDPOINT, id, OPEN_WALLET_METHOD, WALLET_NAME, WALLET_PASSWORD)

txProof = RPCConnector.request(RPC_WALLET_ENDPOINT, id, CHECK_SPEND_PROOF_METHOD, [params[TX_ID], params[MESSAGE], params[SIGNATURE]])

if txProof is None:
logger.printWarning("Could not get any spend proof info from node")
raise rpcerrorhandler.BadRequestError("Could not get any spend proof info from node")

if txProof[PROVEN] == "false":
logger.printWarning("Spent can't be proven")
response = {
PROVEN: False
}

response = {
PROVEN: True
}

err = rpcutils.validateJSONRPCSchema(response, responseSchema)
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

return response


@httputils.getMethod
@rpcutils.rpcMethod
def syncing(id, params):
logger.printInfo(f"Executing RPC method syncing with id {id} and params {params}")

requestSchema, responseSchema = utils.getMethodSchemas(SYNCING)
Expand All @@ -17,14 +266,14 @@ def syncing(id, params):
if err is not None:
raise rpcerrorhandler.BadRequestError(err.message)

blockchainInfo = RPCConnector.request(RPC_ENDPOINT, id, GET_INFO, None)
blockchainInfo = RPCConnector.request(RPC_MONEROD_ENDPOINT, id, GET_INFO_METHOD, None)

if blockchainInfo is None:
logger.printWarning("Could not get blockchain info from node")
raise rpcerrorhandler.BadRequestError("Could not get blockchain info from node")

if not blockchainInfo[SYNCHRONIZED]:
syncInfo = RPCConnector.request(RPC_ENDPOINT, id, GET_SYNC_INFO, None)
syncInfo = RPCConnector.request(RPC_MONEROD_ENDPOINT, id, GET_SYNC_INFO_METHOD, None)

if syncInfo is None:
logger.printWarning("Could not get syncing info from node")
Expand All @@ -35,7 +284,7 @@ def syncing(id, params):
SYNC_PERCENTAGE:
f'{str(syncInfo[HEIGHT] / syncInfo[TARGET_HEIGHT] * 100)}%',
CURRENT_BLOCK_INDEX: str(syncInfo[HEIGHT]),
LATEST_BLOCK_INDEX: str(syncInfo[TARGET_HEIGHT]),
LATEST_BLOCK: str(syncInfo[TARGET_HEIGHT]),
}
else:
response = {SYNCING: False}
Expand Down
12 changes: 11 additions & 1 deletion Connector/xmr/connector.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
#!/usr/bin/python3
from . import utils

RPC_MONEROD_PORT = 38081
RPC_MONEROD_HOST = "monerod"

RPC_WALLET_PORT = 38088
RPC_WALLET_HOST = "wallet"
RPC_MONEROD_ENDPOINT = "json_rpc"

RPC_ENDPOINT = "http://{}:{}/{}".format(RPC_MONEROD_HOST, RPC_MONEROD_PORT, RPC_MONEROD_ENDPOINT)
WALLET_NAME = utils.getWalletName()
WALLET_PASSWORD = "swapper"

RPC_MONEROD_ENDPOINT = "http://{}:{}/{}".format(RPC_MONEROD_HOST, RPC_MONEROD_PORT, RPC_MONEROD_ENDPOINT)
RPC_WALLET_ENDPOINT = "http://{}:{}/{}".format(RPC_WALLET_HOST, RPC_WALLET_PORT, RPC_MONEROD_ENDPOINT)
45 changes: 42 additions & 3 deletions Connector/xmr/constants.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
SYNCING = "syncing"
GET_ADDRESS_BALANCE = "getaddressbalance"
GET_ADDRESSES_BALANCE = "getaddressesbalance"
GET_BLOCK_BY_HASH = "getblockbyhash"
GET_BLOCK_BY_NUMBER = "getblockbynumber"
GET_FEE_PER_BYTE = "getfeeperbyte"
GET_HEIGHT = "getheight"
GET_TRANSACTION = "gettransaction"
CHECK_SPEND_PROOF = "checkSpendProof"
CHECK_TX_PROOF = "checkTxProof"
GET_TX_PROOF = "getTxProof"
GET_SPEND_PROOF = "getSpendProof"

RPC_JSON_SCHEMA_FOLDER = "xmr/rpcschemas/"
WS_JSON_SCHEMA_FOLDER = "xmr/wsschemas/"
Expand All @@ -12,7 +23,35 @@
SYNCHRONIZED = "synchronized"
SYNC_PERCENTAGE = "syncPercentage"
CURRENT_BLOCK_INDEX = "currentBlock"
LATEST_BLOCK_INDEX = "latestBlock"
LATEST_BLOCK_INDEX = "latestBlockIndex"
LATEST_BLOCK_HASH = "latestBlockHash"
LATEST_BLOCK = "latestBlock"
FEE = "fee"
FEE_PER_BYTE = "feePerByte"
HASH = "hash"
BLOCK_HEADER = "block_header"
BLOCK_NUMBER = "blockNumber"
BLOCK_HASH = "blockHash"
TOP_BLOCK_HASH = "top_block_hash"
CONFIRMATIONS = "confirmations"
GOOD = "good"
PROVEN = "proven"
IN_POOL = "in_pool"
IN_POOL_RESPONSE = "inPool"
AMOUNT = "amount"
RECEIVED = "received"
TX_ID = "txid"
ADDRESS = "address"
MESSAGE = "message"
SIGNATURE = "signature"

GET_SYNC_INFO = "sync_info"
GET_INFO = "get_info"
GET_SYNC_INFO_METHOD = "sync_info"
GET_INFO_METHOD = "get_info"
GET_FEE_ESTIMATE_METHOD = "get_fee_estimate"
GET_BLOCK_METHOD = "get_block"
GET_LAST_BLOCK_HEADER_METHOD = "get_last_block_header"
CHECK_TX_PROOF_METHOD = "check_tx_proof"
CHECK_SPEND_PROOF_METHOD = "check_spend_proof"
OPEN_WALLET_METHOD = "open_wallet"
GET_TX_PROOF_METHOD = "get_tx_proof"
GET_SPEND_PROOF_METHOD = "get_spend_proof"
22 changes: 22 additions & 0 deletions Connector/xmr/rpcschemas/checkspendproof_request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"title": "",
"description": "",
"type": "object",
"properties": {
"txid" : {
"type": "string"
},
"message": {
"type": "string"
},
"signature": {
"type": "string"
}
},
"required": [
"txid",
"message",
"signature"
]
}
Loading