680 lines
26 KiB
C++
680 lines
26 KiB
C++
/*
|
|
* This file is part of the Flowee project
|
|
* Copyright (C) 2019 Tom Zander <tom@flowee.org>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "TestApi.h"
|
|
|
|
#include <FloweeServiceApplication.h>
|
|
#include <QNetworkReply>
|
|
#include <QMetaEnum>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QJsonArray>
|
|
#include <QTimer>
|
|
|
|
TestApi::TestApi()
|
|
{
|
|
}
|
|
|
|
void TestApi::start(const QString &hostname, int port)
|
|
{
|
|
m_port = port;
|
|
m_hostname = hostname;
|
|
if (m_hostname.isEmpty())
|
|
m_hostname = QLatin1String("http://localhost");
|
|
else if (m_port == 443)
|
|
m_hostname = "https://" + m_hostname;
|
|
else
|
|
m_hostname = "http://" + m_hostname;
|
|
|
|
// The Qt network access manager will serialize these since they all go to the same host.
|
|
// We create all, but wait for one test to start (the timeout-timer) for the next.
|
|
|
|
m_finishedRequests = 0;
|
|
TestTxBlockHeight::startRequest(this, m_network);
|
|
}
|
|
|
|
QString TestApi::hostname() const
|
|
{
|
|
return m_hostname;
|
|
}
|
|
|
|
int TestApi::port() const
|
|
{
|
|
return m_port;
|
|
}
|
|
|
|
void TestApi::finishedRequest()
|
|
{
|
|
switch (m_finishedRequests++) {
|
|
case 0:
|
|
TestTxBlockHash::startRequest(this, m_network);
|
|
break;
|
|
case 1:
|
|
TestTx::startRequest(this, m_network);
|
|
break;
|
|
case 2:
|
|
TestTx2::startRequest(this, m_network);
|
|
break;
|
|
case 3:
|
|
TestTxCoins::startRequest(this, m_network);
|
|
break;
|
|
case 4:
|
|
TestTxCoins2::startRequest(this, m_network);
|
|
break;
|
|
case 5:
|
|
TestAddressTxs::startRequest(this, m_network);
|
|
break;
|
|
case 6:
|
|
TestAddressOutputs::startRequest(this, m_network);
|
|
break;
|
|
case 7:
|
|
TestAddressBalance::startRequest(this, m_network);
|
|
break;
|
|
case 8:
|
|
QCoreApplication::quit();
|
|
}
|
|
|
|
// TODO
|
|
// TestTxAuthHead::startRequest(this, m_network);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
FloweeServiceApplication app(argc, argv);
|
|
app.setOrganizationName("flowee");
|
|
app.setOrganizationDomain("flowee.org");
|
|
app.setApplicationName("bitcore-proxy-tester");
|
|
|
|
QCommandLineParser parser;
|
|
parser.setApplicationDescription("BitCore proxy test-client");
|
|
parser.addHelpOption();
|
|
app.addClientOptions(parser);
|
|
parser.process(app.arguments());
|
|
|
|
app.setup();
|
|
|
|
logFatal() << "Starting";
|
|
TestApi tester;
|
|
auto server = app.serverAddressFromArguments(3000);
|
|
tester.start(QString::fromStdString(server.hostname), server.announcePort);
|
|
|
|
return app.exec();
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
AbstractTestCall::AbstractTestCall(QNetworkReply *parent)
|
|
: QObject(parent),
|
|
m_reply(parent)
|
|
{
|
|
connect (m_reply, SIGNAL(finished()), this, SLOT(finished()));
|
|
QTimer::singleShot(10000, this, SLOT(timeout()));
|
|
}
|
|
|
|
void AbstractTestCall::startContext(const QString &context)
|
|
{
|
|
m_context = context;
|
|
}
|
|
|
|
void AbstractTestCall::error(const QString &error) {
|
|
m_errors.append({m_context, error});
|
|
}
|
|
|
|
void AbstractTestCall::finished()
|
|
{
|
|
Q_ASSERT(metaObject()->className() != QString("AbstractTestCall"));
|
|
logCritical().nospace() << metaObject()->className() + 4 << " [" << m_reply->url().toString() << "]";
|
|
for (auto x : m_reply->rawHeaderList()) {
|
|
logInfo().nospace() << " " << QString::fromLatin1(x) << ": " << QString::fromUtf8(m_reply->rawHeader(x));
|
|
}
|
|
if (m_reply->error() == QNetworkReply::NoError) {
|
|
QJsonDocument doc = QJsonDocument::fromJson(m_reply->readAll());
|
|
if (doc.isNull())
|
|
error(" document could not be parsed, is it JSON?");
|
|
else
|
|
checkDocument(doc);
|
|
|
|
if (m_errors.isEmpty()) {
|
|
logCritical() << " ✓ all Ok";
|
|
} else {
|
|
for (auto e : m_errors) {
|
|
if (e.context.isEmpty())
|
|
logFatal() << " ❎" << e.error;
|
|
else
|
|
logFatal() << " ❎" << e.context << "|" << e.error;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
logFatal() << " ❎" << m_reply->errorString();
|
|
}
|
|
|
|
deleteLater();
|
|
emit requestDone();
|
|
}
|
|
|
|
void AbstractTestCall::timeout()
|
|
{
|
|
logCritical() << m_reply->url().toString();
|
|
logCritical() << " ❎ Request never returned";
|
|
deleteLater();
|
|
emit requestDone();
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////
|
|
|
|
void TestTxBlockHeight::startRequest(TestApi *parent, QNetworkAccessManager &manager)
|
|
{
|
|
QString blockHeight("%1:%2/api/BCH/mainnet/tx?blockHeight=12");
|
|
auto reply = manager.get(QNetworkRequest(blockHeight.arg(parent->hostname()).arg(parent->port())));
|
|
auto o = new TestTxBlockHeight(reply);
|
|
connect (o, SIGNAL(requestDone()), parent, SLOT(finishedRequest()));
|
|
}
|
|
|
|
void TestTxBlockHeight::checkDocument(const QJsonDocument &doc)
|
|
{
|
|
if (!doc.isArray())
|
|
error("Root should be an array");
|
|
auto root = doc.array();
|
|
if (root.count() != 1)
|
|
error("root-array has incorrect number of items");
|
|
auto tx = root.at(0);
|
|
if (!tx.isObject())
|
|
error("Tx should be an object");
|
|
check(tx, "blockHash", "0000000027c2488e2510d1acf4369787784fa20ee084c258b58d9fbd43802b5e");
|
|
check(tx, "blockTimeNormalized", "2009-01-09T04:21:28.000Z");
|
|
check(tx, "blockHeight", 12);
|
|
check(tx, "chain", "BCH");
|
|
check(tx, "coinbase", true);
|
|
if (!tx["confirmations"].isDouble())
|
|
error("confirmations should be there and be a number");
|
|
check(tx, "inputCount", 1);
|
|
check(tx, "size", 134);
|
|
check(tx, "txid", "3b96bb7e197ef276b85131afd4a09c059cc368133a26ca04ebffb0ab4f75c8b8");
|
|
check(tx, "value", (qint64) 5000000000);
|
|
check(tx, "locktime", -1);
|
|
check(tx, "fee", -1);
|
|
}
|
|
|
|
void TestTxBlockHash::startRequest(TestApi *parent, QNetworkAccessManager &manager)
|
|
{
|
|
QString blockHeight("%1:%2/api/BCH/mainnet/tx?blockHash=0000000027c2488e2510d1acf4369787784fa20ee084c258b58d9fbd43802b5e");
|
|
auto reply = manager.get(QNetworkRequest(blockHeight.arg(parent->hostname()).arg(parent->port())));
|
|
auto o = new TestTxBlockHash(reply);
|
|
connect (o, SIGNAL(requestDone()), parent, SLOT(finishedRequest()));
|
|
}
|
|
|
|
void TestTx::startRequest(TestApi *parent, QNetworkAccessManager &manager)
|
|
{
|
|
QString blockHeight("%1:%2/api/BCH/mainnet/tx/3b96bb7e197ef276b85131afd4a09c059cc368133a26ca04ebffb0ab4f75c8b8");
|
|
auto reply = manager.get(QNetworkRequest(blockHeight.arg(parent->hostname()).arg(parent->port())));
|
|
auto o = new TestTx(reply);
|
|
connect (o, SIGNAL(requestDone()), parent, SLOT(finishedRequest()));
|
|
}
|
|
|
|
void TestTx::checkDocument(const QJsonDocument &doc)
|
|
{
|
|
if (!doc.isObject())
|
|
error("Root should be an object, not an array");
|
|
if (doc["inputs"] != QJsonValue::Undefined)
|
|
error("inputs not expected but present");
|
|
if (doc["outputs"] != QJsonValue::Undefined)
|
|
error("outputs not expected but present");
|
|
|
|
QJsonObject coin = doc.object();
|
|
check(coin, "txid", "3b96bb7e197ef276b85131afd4a09c059cc368133a26ca04ebffb0ab4f75c8b8");
|
|
check(coin, "chain", "BCH");
|
|
check(coin, "network", "mainnet");
|
|
check(coin, "blockHeight", 12);
|
|
check(coin, "blockHash", "0000000027c2488e2510d1acf4369787784fa20ee084c258b58d9fbd43802b5e");
|
|
check(coin, "blockTime", "2009-01-09T04:21:28.000Z");
|
|
check(coin, "blockTimeNormalized", "2009-01-09T04:21:28.000Z");
|
|
check(coin, "coinbase", true);
|
|
check(coin, "locktime", -1);
|
|
check(coin, "inputCount", 1);
|
|
check(coin, "outputCount", 1);
|
|
check(coin, "size", 134);
|
|
check(coin, "fee", -1);
|
|
check(coin, "value", (qint64) 5000000000);
|
|
}
|
|
|
|
void TestTx2::startRequest(TestApi *parent, QNetworkAccessManager &manager)
|
|
{
|
|
QString blockHeight("%1:%2/api/BCH/mainnet/tx/609ea5cb7dd5ae908aaea2bf5a98cc7bb45b85b6e43c6d1dee48f5179ca8efa8");
|
|
auto reply = manager.get(QNetworkRequest(blockHeight.arg(parent->hostname()).arg(parent->port())));
|
|
auto o = new TestTx2(reply);
|
|
connect (o, SIGNAL(requestDone()), parent, SLOT(finishedRequest()));
|
|
}
|
|
|
|
void TestTx2::checkDocument(const QJsonDocument &doc)
|
|
{
|
|
if (!doc.isObject())
|
|
error("Root should be an object, not an array");
|
|
if (doc["inputs"] != QJsonValue::Undefined)
|
|
error("inputs not expected but present");
|
|
if (doc["outputs"] != QJsonValue::Undefined)
|
|
error("outputs not expected but present");
|
|
|
|
QJsonObject coin = doc.object();
|
|
check(coin, "txid", "609ea5cb7dd5ae908aaea2bf5a98cc7bb45b85b6e43c6d1dee48f5179ca8efa8");
|
|
check(coin, "chain", "BCH");
|
|
check(coin, "network", "mainnet");
|
|
check(coin, "blockHeight", 613042);
|
|
check(coin, "blockHash", "00000000000000000057435d2d30474c6c100becff78ff996648caecf8a5f292");
|
|
check(coin, "blockTime", "2019-12-12T15:36:09.000Z");
|
|
check(coin, "blockTimeNormalized", "2019-12-12T15:36:09.000Z");
|
|
check(coin, "coinbase", false);
|
|
check(coin, "locktime", 613040);
|
|
check(coin, "inputCount", 3);
|
|
check(coin, "outputCount", 2);
|
|
check(coin, "size", 520);
|
|
check(coin, "fee", 522);
|
|
check(coin, "value", (qint64) 22646675);
|
|
}
|
|
|
|
void TestTxAuthHead::startRequest(TestApi *parent, QNetworkAccessManager &manager)
|
|
{
|
|
QString blockHeight("%1:%2/api/BCH/mainnet/tx/3b96bb7e197ef276b85131afd4a09c059cc368133a26ca04ebffb0ab4f75c8b8/authhead");
|
|
auto reply = manager.get(QNetworkRequest(blockHeight.arg(parent->hostname()).arg(parent->port())));
|
|
auto o = new TestTxAuthHead(reply);
|
|
connect (o, SIGNAL(requestDone()), parent, SLOT(finishedRequest()));
|
|
}
|
|
|
|
void TestTxAuthHead::checkDocument(const QJsonDocument &doc)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void TestTxCoins::startRequest(TestApi *parent, QNetworkAccessManager &manager)
|
|
{
|
|
QString blockHeight("%1:%2/api/BCH/mainnet/tx/3b96bb7e197ef276b85131afd4a09c059cc368133a26ca04ebffb0ab4f75c8b8/coins");
|
|
auto reply = manager.get(QNetworkRequest(blockHeight.arg(parent->hostname()).arg(parent->port())));
|
|
auto o = new TestTxCoins(reply);
|
|
connect (o, SIGNAL(requestDone()), parent, SLOT(finishedRequest()));
|
|
}
|
|
|
|
void TestTxCoins::checkDocument(const QJsonDocument &doc)
|
|
{
|
|
if (!doc.isObject())
|
|
error("Root should be an object, not an array");
|
|
if (doc["inputs"] == QJsonValue::Undefined)
|
|
error("Missing inputs root item");
|
|
else {
|
|
auto inputs = doc["inputs"].toArray();
|
|
if (inputs.size() > 0)
|
|
error("Coinbase should have no inputs");
|
|
}
|
|
if (doc["outputs"] == QJsonValue::Undefined) {
|
|
error("Missing outputs root item");
|
|
}
|
|
else if (!doc["outputs"].isArray()) {
|
|
error("outputs should be an array");
|
|
} else {
|
|
auto outputs = doc["outputs"].toArray();
|
|
if (outputs.size() != 1)
|
|
error("Incorrect number of coins");
|
|
|
|
auto coin = outputs.at(0);
|
|
check(coin, "address", "qrmn4jkcpxtqa0sp99jrswccfawffglnhgd2tf947a");
|
|
check(coin, "chain", "BCH");
|
|
check(coin, "network", "mainnet");
|
|
check(coin, "coinbase", true);
|
|
check(coin, "confirmations", -1);
|
|
check(coin, "mintHeight", 12);
|
|
check(coin, "spentHeight", -2);
|
|
check(coin, "mintIndex", 0);
|
|
check(coin, "spentTxid", "");
|
|
check(coin, "script", "410478ebe2c28660cd2fa1ba17cc04e58d6312679005a7cad1fd56a7b7f4630bd700bcdb84a888a43fe1a2738ea1f3d2301d02faef357e8a5c35a706e4ae0352a6adac");
|
|
check(coin, "mintTxid", "3b96bb7e197ef276b85131afd4a09c059cc368133a26ca04ebffb0ab4f75c8b8");
|
|
check(coin, "value", (qint64) 5000000000);
|
|
}
|
|
}
|
|
|
|
void TestTxCoins2::startRequest(TestApi *parent, QNetworkAccessManager &manager)
|
|
{
|
|
QString blockHeight("%1:%2/api/BCH/mainnet/tx/dedabaa2b1e6e5fff513bf0a2aeebccf2b650617ff540e4baa27ff3588692acc/coins");
|
|
auto reply = manager.get(QNetworkRequest(blockHeight.arg(parent->hostname()).arg(parent->port())));
|
|
auto o = new TestTxCoins2(reply);
|
|
connect (o, SIGNAL(requestDone()), parent, SLOT(finishedRequest()));
|
|
}
|
|
|
|
void TestTxCoins2::checkDocument(const QJsonDocument &doc)
|
|
{
|
|
if (!doc.isObject())
|
|
error("Root should be an object, not an array");
|
|
if (doc["inputs"] == QJsonValue::Undefined) {
|
|
error("Missing inputs root item");
|
|
} else if (!doc["inputs"].isArray()) {
|
|
error("inputs should be an array");
|
|
} else {
|
|
auto inputs = doc["inputs"].toArray();
|
|
if (inputs.size() != 1)
|
|
error("Incorrect number of coins");
|
|
|
|
startContext("in");
|
|
auto in = inputs.at(0);
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 0);
|
|
check(in, "spentTxid", "dedabaa2b1e6e5fff513bf0a2aeebccf2b650617ff540e4baa27ff3588692acc");
|
|
check(in, "mintTxid", "1a7482a97b77f11d9d6b903512143a20a61a8bc84e2d5b9ff9552ee5eb76c1ca");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 119999);
|
|
check(in, "spentHeight", 120000);
|
|
check(in, "script", "76a914bd9df061f893b011d1640104c2fd817039d0596388ac");
|
|
check(in, "address", "qz7emurplzfmqyw3vsqsfshas9crn5zevv4ha5zcpx");
|
|
check(in, "value", (qint64) 2078000000);
|
|
}
|
|
if (doc["outputs"] == QJsonValue::Undefined) {
|
|
error("Missing outputs root item");
|
|
}
|
|
else if (!doc["outputs"].isArray()) {
|
|
error("outputs should be an array");
|
|
} else {
|
|
auto outputs = doc["outputs"].toArray();
|
|
if (outputs.size() != 2)
|
|
error("Incorrect number of coins");
|
|
|
|
startContext("out/1");
|
|
auto coin = outputs.at(0);
|
|
check(coin, "chain", "BCH");
|
|
check(coin, "network", "mainnet");
|
|
check(coin, "coinbase", false);
|
|
check(coin, "mintIndex", 0);
|
|
check(coin, "spentTxid", "d81a57980bfcec9989e34f85d4c1e8905b940ea0d13949242a2de720d0b5b592");
|
|
check(coin, "mintTxid", "dedabaa2b1e6e5fff513bf0a2aeebccf2b650617ff540e4baa27ff3588692acc");
|
|
check(coin, "mintHeight", 120000);
|
|
check(coin, "spentHeight", 120000);
|
|
check(coin, "address", "qzv0q0gzuxsgu6q08g45nynye77e5pf7pyyckg382y");
|
|
check(coin, "script", "76a91498f03d02e1a08e680f3a2b499264cfbd9a053e0988ac");
|
|
check(coin, "confirmations", -1);
|
|
check(coin, "value", (qint64) 1913000000);
|
|
|
|
startContext("out/2");
|
|
coin = outputs.at(1);
|
|
check(coin, "chain", "BCH");
|
|
check(coin, "network", "mainnet");
|
|
check(coin, "coinbase", false);
|
|
check(coin, "mintIndex", 1);
|
|
check(coin, "spentTxid", "d6e9a30346bea29fd6352f34273c971f6b3615f4c4e5912be210d61073e210d1");
|
|
check(coin, "mintTxid", "dedabaa2b1e6e5fff513bf0a2aeebccf2b650617ff540e4baa27ff3588692acc");
|
|
check(coin, "mintHeight", 120000);
|
|
check(coin, "spentHeight", 132894);
|
|
check(coin, "address", "qpzyy54tcur68pp8drfdhjpqpxdjfquqh5vs35c4r8");
|
|
check(coin, "script", "76a914444252abc707a3842768d2dbc820099b248380bd88ac");
|
|
check(coin, "confirmations", -1);
|
|
check(coin, "value", (qint64) 165000000);
|
|
}
|
|
}
|
|
|
|
void TestAddressTxs::startRequest(TestApi *parent, QNetworkAccessManager &manager)
|
|
{
|
|
QString addressTxs("%1:%2/api/BCH/mainnet/address/qruexuvmqwc0cd7padx2qhvrdlmygefdnv2cqjpvq6/txs");
|
|
auto reply = manager.get(QNetworkRequest(addressTxs.arg(parent->hostname()).arg(parent->port())));
|
|
auto o = new TestAddressTxs(reply);
|
|
connect (o, SIGNAL(requestDone()), parent, SLOT(finishedRequest()));
|
|
}
|
|
|
|
void TestAddressTxs::checkDocument(const QJsonDocument &doc)
|
|
{
|
|
if (!doc.isArray()) {
|
|
error("Root should be an array, not an object");
|
|
return;
|
|
}
|
|
auto txs = doc.array();
|
|
if (txs.size() != 10)
|
|
error("Incorrect number of txs");
|
|
|
|
startContext("tx1");
|
|
auto in = txs.at(0);
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 1);
|
|
check(in, "spentTxid", "027e6a10e209a1cd16f2fbaa44c4c4da131fc9b58d228fe8b8e852f08d96df96");
|
|
check(in, "mintTxid", "64dc2d189afdc07e65ef60ae80646769c1edf58dcdd05e4556d8291af33964e0");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 229375);
|
|
check(in, "spentHeight", 229612);
|
|
check(in, "script", "76a914f993719b03b0fc37c1eb4ca05d836ff644652d9b88ac");
|
|
check(in, "address", "qruexuvmqwc0cd7padx2qhvrdlmygefdnv2cqjpvq6");
|
|
check(in, "value", (qint64) 2737777);
|
|
|
|
startContext("tx2");
|
|
in = txs.at(1);
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 1);
|
|
check(in, "spentTxid", "71a63a90a8deb304fcd7a225329ebee1c84f9bf49ecd156f88c9c845df4276bc");
|
|
check(in, "mintTxid", "c924a04c7086d7c91f4e9498f389b474c5b911e4eab1467ac73af44d17999fcd");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 136196);
|
|
check(in, "spentHeight", 136198);
|
|
check(in, "script", "76a914f993719b03b0fc37c1eb4ca05d836ff644652d9b88ac");
|
|
check(in, "address", "qruexuvmqwc0cd7padx2qhvrdlmygefdnv2cqjpvq6");
|
|
check(in, "value", (qint64) 1000000);
|
|
|
|
startContext("tx3");
|
|
in = txs.at(2);
|
|
check(in, "chain", "BCH");
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 1);
|
|
check(in, "spentTxid", "98d8d54bf22f1aba20653763359b7f0f3c386e95f7db525b48bba12f79b61fae");
|
|
check(in, "mintTxid", "442d6116a9d1ab3616ad0f4a8b49bcfb305e285de8d6cafc9ddc86c1653136a4");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 130844);
|
|
check(in, "spentHeight", 131731);
|
|
check(in, "script", "76a914f993719b03b0fc37c1eb4ca05d836ff644652d9b88ac");
|
|
check(in, "address", "qruexuvmqwc0cd7padx2qhvrdlmygefdnv2cqjpvq6");
|
|
check(in, "value", (qint64) 2000000);
|
|
|
|
startContext("tx4");
|
|
in = txs.at(3);
|
|
check(in, "chain", "BCH");
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 1);
|
|
check(in, "spentTxid", "98d8d54bf22f1aba20653763359b7f0f3c386e95f7db525b48bba12f79b61fae");
|
|
check(in, "mintTxid", "9de4539e1ddf1590a3000803ea23f5c06521fb12a52af00a1c1a9b12b1289025");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 129751);
|
|
check(in, "spentHeight", 131731);
|
|
check(in, "script", "76a914f993719b03b0fc37c1eb4ca05d836ff644652d9b88ac");
|
|
check(in, "address", "qruexuvmqwc0cd7padx2qhvrdlmygefdnv2cqjpvq6");
|
|
check(in, "value", (qint64) 2000000);
|
|
|
|
startContext("tx5");
|
|
in = txs.at(4);
|
|
check(in, "chain", "BCH");
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 1);
|
|
check(in, "spentTxid", "659ff8192ab24cf9d44b8038f110d8f56f0a0e1757c5b4993d43d162fc29f0e2");
|
|
check(in, "mintTxid", "f301b2ae513c204447b4de50534628b94ade0f0102fa489d30e4d1147c802c85");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 128371);
|
|
check(in, "spentHeight", 128379);
|
|
check(in, "script", "76a914f993719b03b0fc37c1eb4ca05d836ff644652d9b88ac");
|
|
check(in, "address", "qruexuvmqwc0cd7padx2qhvrdlmygefdnv2cqjpvq6");
|
|
check(in, "value", (qint64) 1000000);
|
|
|
|
startContext("tx6");
|
|
in = txs.at(5);
|
|
check(in, "chain", "BCH");
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 1);
|
|
check(in, "spentTxid", "659ff8192ab24cf9d44b8038f110d8f56f0a0e1757c5b4993d43d162fc29f0e2");
|
|
check(in, "mintTxid", "fd0a73093c671e787cf46e8bfc9f794b2ddbe38dadd60009571cf2ceac49033d");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 128040);
|
|
check(in, "spentHeight", 128379);
|
|
check(in, "script", "76a914f993719b03b0fc37c1eb4ca05d836ff644652d9b88ac");
|
|
check(in, "address", "qruexuvmqwc0cd7padx2qhvrdlmygefdnv2cqjpvq6");
|
|
check(in, "value", (qint64) 1000000);
|
|
|
|
startContext("tx7");
|
|
in = txs.at(6);
|
|
check(in, "chain", "BCH");
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 1);
|
|
check(in, "spentTxid", "659ff8192ab24cf9d44b8038f110d8f56f0a0e1757c5b4993d43d162fc29f0e2");
|
|
check(in, "mintTxid", "455a4ccc23dbbe75789e4abe7fb516bce07f9c753b7d0066a049fa6170bb4951");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 127835);
|
|
check(in, "spentHeight", 128379);
|
|
check(in, "script", "76a914f993719b03b0fc37c1eb4ca05d836ff644652d9b88ac");
|
|
check(in, "address", "qruexuvmqwc0cd7padx2qhvrdlmygefdnv2cqjpvq6");
|
|
check(in, "value", (qint64) 7000000);
|
|
|
|
startContext("tx8");
|
|
in = txs.at(7);
|
|
check(in, "chain", "BCH");
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 1);
|
|
check(in, "spentTxid", "659ff8192ab24cf9d44b8038f110d8f56f0a0e1757c5b4993d43d162fc29f0e2");
|
|
check(in, "mintTxid", "9168546209cfca11a8ac3a1f32213457d37ad6c5fdf568639de258d1c79f7d7e");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 127025);
|
|
check(in, "spentHeight", 128379);
|
|
check(in, "script", "76a914f993719b03b0fc37c1eb4ca05d836ff644652d9b88ac");
|
|
check(in, "address", "qruexuvmqwc0cd7padx2qhvrdlmygefdnv2cqjpvq6");
|
|
check(in, "value", (qint64) 13000000);
|
|
|
|
startContext("tx9");
|
|
in = txs.at(8);
|
|
check(in, "chain", "BCH");
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 1);
|
|
check(in, "spentTxid", "1552efb5838378ca5f5d3d55dda06757f4fc679a7cc431affa2b5247e9956502");
|
|
check(in, "mintTxid", "bfc6148e1c420935fc21e4543dda4d7fefbe2828559c4109e06796afab2cf1f9");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 125786);
|
|
check(in, "spentHeight", 125896);
|
|
check(in, "script", "76a914f993719b03b0fc37c1eb4ca05d836ff644652d9b88ac");
|
|
check(in, "address", "qruexuvmqwc0cd7padx2qhvrdlmygefdnv2cqjpvq6");
|
|
check(in, "value", (qint64) 3000000);
|
|
|
|
startContext("tx10");
|
|
in = txs.at(9);
|
|
check(in, "chain", "BCH");
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 1);
|
|
check(in, "spentTxid", "1552efb5838378ca5f5d3d55dda06757f4fc679a7cc431affa2b5247e9956502");
|
|
check(in, "mintTxid", "2d18a9a278ac1afe4bc458fd286fe576fdea722a969e9113da474cc967146b76");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 125456);
|
|
check(in, "spentHeight", 125896);
|
|
check(in, "script", "76a914f993719b03b0fc37c1eb4ca05d836ff644652d9b88ac");
|
|
check(in, "address", "qruexuvmqwc0cd7padx2qhvrdlmygefdnv2cqjpvq6");
|
|
check(in, "value", (qint64) 21000000);
|
|
}
|
|
|
|
void TestAddressOutputs::startRequest(TestApi *parent, QNetworkAccessManager &manager)
|
|
{
|
|
QString addressTxs("%1:%2/api/BCH/mainnet/address/1PYELM7jXHy5HhatbXGXfRpGrgMMxmpobu/?unspent=true");
|
|
auto reply = manager.get(QNetworkRequest(addressTxs.arg(parent->hostname()).arg(parent->port())));
|
|
auto o = new TestAddressOutputs(reply);
|
|
connect (o, SIGNAL(requestDone()), parent, SLOT(finishedRequest()));
|
|
}
|
|
|
|
void TestAddressOutputs::checkDocument(const QJsonDocument &doc)
|
|
{
|
|
/*
|
|
* This address mixes p2pk and p2pkh outputs.
|
|
* At this time I chose to make the proxy not search for public-keys, but only for public-key-hash
|
|
* style addresses. As that would be a lot of extra complexity and practically nobody needs this.
|
|
*/
|
|
if (!doc.isArray()) {
|
|
error("Root should be an array, not an object");
|
|
return;
|
|
}
|
|
auto txs = doc.array();
|
|
if (txs.size() != 3)
|
|
error("Incorrect number of txs");
|
|
|
|
startContext("out1");
|
|
auto in = txs.at(1);
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 1);
|
|
check(in, "spentTxid", "");
|
|
check(in, "address", "qrmn4jkcpxtqa0sp99jrswccfawffglnhgd2tf947a");
|
|
check(in, "mintTxid", "ef3cbd9631b13794ae2a5b38ee33f987a0a681a616b455b8b8d1819894c8b329");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 465282);
|
|
check(in, "spentHeight", -2);
|
|
check(in, "script", "76a914f73acad809960ebe012964383b184f5c94a3f3ba88ac");
|
|
check(in, "value", (qint64) 12213);
|
|
|
|
startContext("out2");
|
|
in = txs.at(2);
|
|
check(in, "chain", "BCH");
|
|
check(in, "network", "mainnet");
|
|
check(in, "coinbase", false);
|
|
check(in, "mintIndex", 1);
|
|
check(in, "spentTxid", "");
|
|
check(in, "address", "qrmn4jkcpxtqa0sp99jrswccfawffglnhgd2tf947a");
|
|
check(in, "mintTxid", "7307aa053fee854a50e432e07f177fc0ab012f4b584daf02b5a81f71cb54a117");
|
|
check(in, "confirmations", -1);
|
|
check(in, "mintHeight", 427269);
|
|
check(in, "spentHeight", -2);
|
|
check(in, "script", "76a914f73acad809960ebe012964383b184f5c94a3f3ba88ac");
|
|
check(in, "value", (qint64) 100000);
|
|
}
|
|
|
|
void TestAddressBalance::startRequest(TestApi *parent, QNetworkAccessManager &manager)
|
|
{
|
|
QString addressTxs("%1:%2/api/BCH/mainnet/address/qq0h24aghvfdge6cq8cs8ct3t53slgzm7grngua3ds/balance");
|
|
auto reply = manager.get(QNetworkRequest(addressTxs.arg(parent->hostname()).arg(parent->port())));
|
|
auto o = new TestAddressBalance(reply);
|
|
connect (o, SIGNAL(requestDone()), parent, SLOT(finishedRequest()));
|
|
}
|
|
|
|
void TestAddressBalance::checkDocument(const QJsonDocument &doc)
|
|
{
|
|
if (doc.isArray()) {
|
|
error("Root should be an object, not an array");
|
|
return;
|
|
}
|
|
auto object = doc.object();
|
|
check(object, "confirmed", (qint64) 7800);
|
|
check(object, "unconfirmed", (qint64) 0);
|
|
check(object, "balance", (qint64) 7800);
|
|
}
|