Skip to content
Merged
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
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
cmake_minimum_required(VERSION 3.12)
project(qubic-cli CXX)
set (CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# keep the lists sorted alphabetically
SET(FILES ${CMAKE_SOURCE_DIR}/asset_utils.cpp
Expand Down
6 changes: 3 additions & 3 deletions asset_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ std::vector<RespondOwnedAssets> getOwnedAsset(const char * nodeIp, const int nod
packet.header.randomizeDejavu();
packet.header.setType(REQUEST_OWNED_ASSETS);
auto qc = make_qc(nodeIp, nodePort);
qc->sendData((uint8_t *) &packet, packet.header.size());
qc->sendData(packet);

return qc->getLatestVectorPacketAs<RespondOwnedAssets>();
}
Expand All @@ -74,7 +74,7 @@ std::vector<RespondPossessedAssets> getPossessionAsset(const char * nodeIp, cons
packet.header.randomizeDejavu();
packet.header.setType(REQUEST_POSSESSED_ASSETS);
auto qc = make_qc(nodeIp, nodePort);
qc->sendData((uint8_t *) &packet, packet.header.size());
qc->sendData(packet);

return qc->getLatestVectorPacketAs<RespondPossessedAssets>();
}
Expand Down Expand Up @@ -405,7 +405,7 @@ void printAssetRecords(const char* nodeIp, const int nodePort, const char* reque
}

auto qc = make_qc(nodeIp, nodePort);
qc->sendData((uint8_t*)&packet, packet.header.size());
qc->sendData(std::span<const uint8_t>(reinterpret_cast<const uint8_t*>(&packet), packet.header.size()), packet.header.size());

bool receivedResponses = false;
if (withSiblings)
Expand Down
41 changes: 27 additions & 14 deletions connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <arpa/inet.h>
#include <unistd.h>
#endif

#include <algorithm>
#include <cstring>
#include <string>
#include <stdexcept>
Expand Down Expand Up @@ -151,8 +153,11 @@ QubicConnection::~QubicConnection()
}

// Receive the requested number of bytes (sz) or less if sz bytes have not been received after timeout. Return number of received bytes.
int QubicConnection::receiveData(uint8_t* buffer, int sz)
int QubicConnection::receiveData(std::span<uint8_t> buffer, unsigned int sz)
{
if (sz > buffer.size())
throw std::logic_error("Buffer size is smaller than requested size.");

int totalRecvSz = 0;
while (sz)
{
Expand All @@ -166,7 +171,7 @@ int QubicConnection::receiveData(uint8_t* buffer, int sz)
// "For connection-oriented sockets (type SOCK_STREAM for example), calling recv will
// return as much data as is currently available up to the size of the buffer specified. [...]
// If no incoming data is available at the socket, the recv call blocks and waits for data to arrive [...]"
int recvSz = recv(mSocket, (char*)buffer + totalRecvSz, sz, 0);
int recvSz = recv(mSocket, (char*)buffer.data() + totalRecvSz, sz, 0);
if (recvSz <= 0)
{
// timeout, closed connection, or other error
Expand All @@ -178,7 +183,7 @@ int QubicConnection::receiveData(uint8_t* buffer, int sz)
return totalRecvSz;
}

int QubicConnection::receiveAllDataOrThrowException(uint8_t* buffer, int sz)
int QubicConnection::receiveAllDataOrThrowException(std::span<uint8_t> buffer, unsigned int sz)
{
int recvSz = receiveData(buffer, sz);
if (recvSz != sz)
Expand Down Expand Up @@ -213,7 +218,7 @@ void QubicConnection::receivePacketWithHeaderAs(T& result)
int recvByte = -1, packetSize = -1, remainingSize = -1;
while (true)
{
recvByte = receiveData((uint8_t*)&header, sizeof(RequestResponseHeader));
recvByte = receiveData(header);
if (recvByte != sizeof(RequestResponseHeader))
{
throw std::logic_error("No connection.");
Expand All @@ -239,9 +244,9 @@ void QubicConnection::receivePacketWithHeaderAs(T& result)
memset(&result, 0, sizeof(T));
if (remainingSize)
{
memset(mBuffer, 0, sizeof(T));
std::fill_n(mBuffer.begin(), remainingSize, 0);
receiveAllDataOrThrowException(mBuffer, remainingSize);
result = *((T*)mBuffer);
result = *((T*)mBuffer.data());
}
}

Expand All @@ -257,7 +262,7 @@ T QubicConnection::receivePacketAs()
{
throw std::logic_error("Unexpected data size.");
}
result = *((T*)mBuffer);
result = *((T*)mBuffer.data());
return result;
}

Expand All @@ -284,28 +289,36 @@ std::vector<T> QubicConnection::getLatestVectorPacketAs()
return results;
}

int QubicConnection::sendData(uint8_t* buffer, int sz)
int QubicConnection::sendData(std::span<const uint8_t> buffer, unsigned int sz)
{
if (sz > buffer.size())
{
throw std::logic_error("Buffer size is smaller than requested send size.");
}
// also skip printing packets of size 8 (typically used during the preparation step, not the final stage)
if (!std::string(g_printToScreen).empty() && sz != 8) {
if (!std::string(g_printToScreen).empty() && sz != 8)
{
std::string printType = g_printToScreen;
// Do not print the first 8 bytes (header)
printBytes(buffer + 8, sz - 8, printType);
printBytes(buffer.data() + 8, sz - 8, printType);

// this operation may break the normal flow, we need to skip printing error messages to console
if (!std::freopen("/dev/null", "w", stdout)) {}
if (!std::freopen("/dev/null", "w", stderr)) {}
return 0;
} else {
}
else
{
int size = sz;
int numberOfBytes;
while (size)
int offset = 0;
while (size > 0)
{
if ((numberOfBytes = send(mSocket, (char*)buffer, size, 0)) <= 0)
if ((numberOfBytes = send(mSocket, (const char*)buffer.data() + offset, size, 0)) <= 0)
{
return 0;
}
buffer += numberOfBytes;
offset += numberOfBytes;
size -= numberOfBytes;
}
return sz - size;
Expand Down
47 changes: 40 additions & 7 deletions connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,19 @@
#include <vector>
#include <memory>
#include <stdexcept>
#include <array>
#include <span>
#include <type_traits>

#define DEFAULT_TIMEOUT_MSEC 1000

// Custom concept to detect if something behaves like a pointer (raw or smart)
template <typename T>
concept IsPointerLike = std::is_pointer_v<T> || requires(T t)
{
t.operator->();
};

// Not thread safe
class QubicConnection
{
Expand All @@ -20,13 +30,36 @@ class QubicConnection

// Receive at most sz bytes and write them to buffer. Return the actual number of received bytes.
// Should only return less than sz bytes on timeout, closed connection, or error.
int receiveData(uint8_t* buffer, int sz);
// Throws std::logic_error if sz > buffer.size().
int receiveData(std::span<uint8_t> buffer, unsigned int sz);

// Receive sz bytes and write them to buffer. Throws std::logic_error if sz bytes cannot be read.
int receiveAllDataOrThrowException(uint8_t* buffer, int sz);

// Send sz bytes contained in buffer.
int sendData(uint8_t* buffer, int sz);
// Receive an object of type T. Return the actual number of received bytes.
// Should only return less than sz bytes on timeout, closed connection, or error.
// This template only accepts trivially copyable types that are no ranges or pointers.
template <typename T>
requires std::is_trivially_copyable_v<T>
&& (!std::ranges::range<T>)
&& (!IsPointerLike<T>)
int receiveData(T& obj)
{
return receiveData(std::span<uint8_t>(reinterpret_cast<uint8_t*>(&obj), sizeof(T)), sizeof(T));
}

// Receive sz bytes and write them to the buffer. Throws std::logic_error if sz bytes cannot be read.
int receiveAllDataOrThrowException(std::span<uint8_t> buffer, unsigned int sz);

// Send sz bytes contained in buffer. Throws std::logic_error if sz > buffer.size().
int sendData(std::span<const uint8_t> buffer, unsigned int sz);

// Send an object of type T. This template only accepts trivially copyable types that are no ranges or pointers.
template <typename T>
requires std::is_trivially_copyable_v<T>
&& (!std::ranges::range<T>)
&& (!IsPointerLike<T>)
int sendData(const T& obj)
{
return sendData(std::span<const uint8_t>(reinterpret_cast<const uint8_t*>(&obj), sizeof(T)), sizeof(T));
}

//void receiveDataAll(std::vector<uint8_t>& buffer);
void getHandshakeData(std::vector<uint8_t>& buffer);
Expand All @@ -48,7 +81,7 @@ class QubicConnection
char mNodeIp[32];
int mNodePort;
int mSocket;
uint8_t mBuffer[0xFFFFFF];
std::array<uint8_t, 0xFFFFFF> mBuffer;
std::vector<uint8_t> mHandshakeData; // storing handshake data after open a connection
};

Expand Down
2 changes: 1 addition & 1 deletion defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#define DEFAULT_SCHEDULED_TICK_OFFSET 8
#define DEFAULT_NODE_PORT 21841
#define DEFAULT_NODE_IP "127.0.0.1"
#define NUMBER_OF_TRANSACTIONS_PER_TICK 4096
#define NUMBER_OF_TRANSACTIONS_PER_TICK 4096ULL
#define SIGNATURE_SIZE 64
#define MAX_INPUT_SIZE 1024ULL
#define MAX_TRANSACTION_SIZE (MAX_INPUT_SIZE + sizeof(Transaction) + SIGNATURE_SIZE)
Expand Down
70 changes: 33 additions & 37 deletions escrow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ void escrowCreateDeal(const char* nodeIp, int nodePort, const char* seed,
packet.header.setSize(sizeof(packet));
packet.header.zeroDejavu();
packet.header.setType(BROADCAST_TRANSACTION);
qc->sendData((uint8_t*)&packet, packet.header.size());
qc->sendData(packet);
KangarooTwelve((uint8_t*)&packet.transaction,
sizeof(packet.transaction) + sizeof(input) + SIGNATURE_SIZE,
digest,
Expand Down Expand Up @@ -207,40 +207,38 @@ int64_t escrowGetSharesFeesForDeal(const char* nodeIp, int nodePort, const char*

EscrowGetDeals_output escrowGetDealsOutput(const char* nodeIp, int nodePort, const char* seed, const int64_t proposedOffset, const int64_t publicOffset)
{
EscrowGetDeals_input input;
struct {
RequestResponseHeader header;
RequestContractFunction rcf;
EscrowGetDeals_input input;
} req;
memset(&req, 0, sizeof(req));

uint8_t subseed[32] = { 0 };
uint8_t privateKey[32] = { 0 };
uint8_t sourcePublicKey[32] = { 0 };
getSubseedFromSeed((uint8_t*) seed, subseed);
getPrivateKeyFromSubSeed(subseed, privateKey);
getPublicKeyFromPrivateKey(privateKey, sourcePublicKey);
memset(input.owner, 0, 32);
memcpy(input.owner, sourcePublicKey, 32);
input.proposedOffset = proposedOffset;
input.publicOffset = publicOffset;
memset(req.input.owner, 0, 32);
memcpy(req.input.owner, sourcePublicKey, 32);
req.input.proposedOffset = proposedOffset;
req.input.publicOffset = publicOffset;

auto qc = make_qc(nodeIp, nodePort);
if (!qc) {
LOG("Failed to connect to node.\n");
return EscrowGetDeals_output{};
}

struct {
RequestResponseHeader header;
RequestContractFunction rcf;
EscrowGetDeals_input in;
} req;

memset(&req, 0, sizeof(req));
req.rcf.contractIndex = ESCROW_CONTRACT_INDEX;
req.rcf.inputType = ESCROW_GET_DEALS;
req.rcf.inputSize = sizeof(input);
memcpy(&req.in, &input, sizeof(input));
req.header.setSize(sizeof(req.header) + sizeof(req.rcf) + sizeof(input));
req.rcf.inputSize = sizeof(req.input);
req.header.setSize(sizeof(req));
req.header.randomizeDejavu();
req.header.setType(RequestContractFunction::type());

qc->sendData((uint8_t*)&req, req.header.size());
qc->sendData(req);

EscrowGetDeals_output output;
memset(&output, 0, sizeof(output));
Expand Down Expand Up @@ -332,7 +330,7 @@ void escrowOperateDeal(const char* nodeIp, int nodePort, const char* seed, const
packet.header.setSize(sizeof(packet));
packet.header.zeroDejavu();
packet.header.setType(BROADCAST_TRANSACTION);
qc->sendData((uint8_t*)&packet, packet.header.size());
qc->sendData(packet);
KangarooTwelve((uint8_t*)&packet.transaction,
sizeof(packet.transaction) + sizeof(input) + SIGNATURE_SIZE,
digest,
Expand Down Expand Up @@ -402,7 +400,7 @@ void escrowTransferRights(const char* nodeIp, int nodePort, const char* seed, co
packet.header.setSize(sizeof(packet));
packet.header.zeroDejavu();
packet.header.setType(BROADCAST_TRANSACTION);
qc->sendData((uint8_t*)&packet, packet.header.size());
qc->sendData(packet);
KangarooTwelve((uint8_t*)&packet.transaction,
sizeof(packet.transaction) + sizeof(input) + SIGNATURE_SIZE,
digest,
Expand All @@ -416,7 +414,13 @@ void escrowTransferRights(const char* nodeIp, int nodePort, const char* seed, co

void escrowGetFreeAsset(const char* nodeIp, int nodePort, const char* seed, const char* assetName, const char* issuer)
{
EscrowGetFreeAsset_input input;
struct {
RequestResponseHeader header;
RequestContractFunction rcf;
EscrowGetFreeAsset_input input;
} req;
memset(&req, 0, sizeof(req));

uint8_t subseed[32] = { 0 };
uint8_t privateKey[32] = { 0 };
uint8_t sourcePublicKey[32] = { 0 };
Expand All @@ -426,35 +430,27 @@ void escrowGetFreeAsset(const char* nodeIp, int nodePort, const char* seed, cons
getPublicKeyFromPrivateKey(privateKey, pk);
getPublicKeyFromIdentity(issuer, sourcePublicKey);

memset(input.owner, 0, 32);
memcpy(input.owner, pk, 32);
memset(input.asset.issuer, 0, 32);
memcpy(input.asset.issuer, sourcePublicKey, 32);
memset(&input.asset.assetName, 0, 8);
memcpy(&input.asset.assetName, assetName, std::min(strlen(assetName), (size_t) 7));
memset(req.input.owner, 0, 32);
memcpy(req.input.owner, pk, 32);
memset(req.input.asset.issuer, 0, 32);
memcpy(req.input.asset.issuer, sourcePublicKey, 32);
memset(&req.input.asset.assetName, 0, 8);
memcpy(&req.input.asset.assetName, assetName, std::min(strlen(assetName), (size_t) 7));

auto qc = make_qc(nodeIp, nodePort);
if (!qc) {
LOG("Failed to connect to node.\n");
return;
}

struct {
RequestResponseHeader header;
RequestContractFunction rcf;
EscrowGetFreeAsset_input in;
} req;

memset(&req, 0, sizeof(req));
req.rcf.contractIndex = ESCROW_CONTRACT_INDEX;
req.rcf.inputType = ESCROW_GET_FREE_ASSET;
req.rcf.inputSize = sizeof(input);
memcpy(&req.in, &input, sizeof(input));
req.header.setSize(sizeof(req.header) + sizeof(req.rcf) + sizeof(input));
req.rcf.inputSize = sizeof(req.input);
req.header.setSize(sizeof(req));
req.header.randomizeDejavu();
req.header.setType(RequestContractFunction::type());

qc->sendData((uint8_t*)&req, req.header.size());
qc->sendData(req);

EscrowGetFreeAsset_output output;
memset(&output, 0, sizeof(output));
Expand Down
4 changes: 2 additions & 2 deletions file_upload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ bool uploadHeader(QCPtr& qc, const char* seed, size_t fileSize, int numberOfFrag
payload.header.setType(BROADCAST_TRANSACTION);

signData(seed, (uint8_t*)&payload.fh, sizeof(payload.fh) - SIGNATURE_SIZE, payload.fh.signature);
qc->sendData((uint8_t *) &payload, payload.header.size());
qc->sendData(payload);

KangarooTwelve((uint8_t*)&payload.fh, sizeof(payload.fh), txHash, 32);
LOG("Waiting for tx to be included at tick %d\n", txTick);
Expand Down Expand Up @@ -125,7 +125,7 @@ bool uploadFragment(QCPtr& qc, const char* seed, const uint64_t fragmentId,
payload.header.setType(BROADCAST_TRANSACTION);
signData(seed, (uint8_t*)&payload.fftp, sizeof(FileFragmentTransactionPrefix) + fragmentSize, ptr_signature);

qc->sendData((uint8_t *) &payload, payload.header.size());
qc->sendData(std::span<const uint8_t>(reinterpret_cast<const uint8_t*>(&payload), payloadSize), static_cast<unsigned int>(payloadSize));
KangarooTwelve((uint8_t*)&payload.fftp, uint16_t(sizeof(FileFragmentTransactionPrefix) + fragmentSize + SIGNATURE_SIZE), outTxHash, 32);
LOG("Waiting for tx to be included at tick %d\n", txTick);
currentTick = getTickNumberFromNode(qc);
Expand Down
Loading
Loading