Skip to content

Instantly share code, notes, and snippets.

@sleepdefic1t
Created November 29, 2019 23:18
Show Gist options
  • Save sleepdefic1t/61219a3cec777178cd1e359aa0d0cc71 to your computer and use it in GitHub Desktop.
Save sleepdefic1t/61219a3cec777178cd1e359aa0d0cc71 to your computer and use it in GitHub Desktop.
Radians C++ Scooter Registration Implementation
cmake_minimum_required(VERSION 3.2)
project(ark_cpp_crypto C CXX)
# ------------------------------------------------------------------------------
# External Libraries
# ------------------------------------------------------------------------------
include(${CMAKE_SOURCE_DIR}/cmake/External.cmake)
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Internal Libraries
# ------------------------------------------------------------------------------
set(INTERNAL_LIBRARY_SOURCE_DIRS
${PROJECT_SOURCE_DIR}/lib/bcl
${PROJECT_SOURCE_DIR}/lib/rfc6979
)
include_directories(${INTERNAL_LIBRARY_SOURCE_DIRS})
# ------------------------------------------------------------------------------
# Nayuki's Bitcoin Cryptography Library
set(BCL_SOURCE
lib/bcl/Base58Check.cpp
lib/bcl/CurvePoint.cpp
lib/bcl/Ecdsa.cpp
lib/bcl/FieldInt.cpp
lib/bcl/Ripemd160.cpp
lib/bcl/Sha256Hash.cpp
lib/bcl/Sha256.cpp
lib/bcl/Sha512.cpp
lib/bcl/Uint256.cpp
lib/bcl/Utils.cpp
)
set(INTERNAL_LIBRARY_SOURCE ${BCL_SOURCE})
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# ARK C++ Crypto Source
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Common
set(COMMON_SOURCE
common/configuration.cpp
common/network.cpp
)
# ------------------------------------------------------------------------------
# Crypto
set(CRYPTO_SOURCE
crypto/curve.cpp
crypto/hash.cpp
crypto/message.cpp
crypto/slot.cpp
)
# ------------------------------------------------------------------------------
# Identities
set(IDENTITIES_SOURCE
identities/address.cpp
identities/keys.cpp
identities/privatekey.cpp
identities/publickey.cpp
identities/wif.cpp
)
# ------------------------------------------------------------------------------
# Transactions
# Types
set(TRANSACTIONS_TYPES_SOURCE
transactions/types/transfer.cpp
transactions/types/second_signature.cpp
transactions/types/delegate_registration.cpp
transactions/types/vote.cpp
# transactions/types/multi_signature.cpp
transactions/types/ipfs.cpp
transactions/types/multi_payment.cpp
transactions/types/htlc_lock.cpp
transactions/types/htlc_claim.cpp
transactions/types/htlc_refund.cpp
transactions/types/scooter_registration.cpp
)
# Serialization/Deserialization
set(TRANSACTIONS_SERDE_SOURCE
transactions/deserializer.cpp
transactions/serializer.cpp
)
# Transaction Source Files
set(TRANSACTIONS_SOURCE
${TRANSACTIONS_TYPES_SOURCE}
${TRANSACTIONS_SERDE_SOURCE}
transactions/transaction.cpp
)
# ------------------------------------------------------------------------------
# Utils
set(UTILS_SOURCE utils/base58.cpp)
# ------------------------------------------------------------------------------
# ARK C++ Crypto Library Source
set(ARK_LIBRARY_SOURCE
${COMMON_SOURCE}
${CRYPTO_SOURCE}
${IDENTITIES_SOURCE}
${TRANSACTIONS_SOURCE}
${UTILS_SOURCE}
)
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Add the Source Files to the Library
# ------------------------------------------------------------------------------
add_library(${PROJECT_NAME} STATIC
${EXTERNAL_LIBRARY_SOURCE}
${INTERNAL_LIBRARY_SOURCE}
${ARK_LIBRARY_SOURCE}
)
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Set the Include Folders
# ------------------------------------------------------------------------------
set(ARK_CPP_CRYPTO_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/include/cpp-crypto
${PROJECT_SOURCE_DIR}/lib/
)
include_directories(${ARK_CPP_CRYPTO_INCLUDE_DIRS})
target_include_directories(${PROJECT_NAME} PUBLIC ${ARK_CPP_CRYPTO_INCLUDE_DIRS})
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Windows: Link to `crypt32`
# ------------------------------------------------------------------------------
if (MSVC)
target_link_libraries(${PROJECT_NAME} PUBLIC crypt32)
endif()
# ------------------------------------------------------------------------------
/**
* This file is part of Ark Cpp Crypto.
*
* (c) Ark Ecosystem <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
**/
#ifndef ARK_TRANSACTIONS_BUILDERS_SCOOTER_REGISTRATION_HPP
#define ARK_TRANSACTIONS_BUILDERS_SCOOTER_REGISTRATION_HPP
#include <string>
#include "transactions/builders/common.hpp"
namespace Ark {
namespace Crypto {
namespace transactions {
namespace builder {
////////////////////////////////////////////////////////////////////////////////
// Forward Declaration
class ScooterRegistration;
////////////////////////////////////////////////////////////////////////////////
class ScooterRegistration : public Common<ScooterRegistration> {
public:
////////////////////////////////////////////////////////////////////////////
// Amount
ScooterRegistration &scooterId(const std::string &scooterId) {
this->transaction.data.asset.scooterRegistration.scooterId = scooterId;
return *this;
}
};
} // namespace builder
} // namespace transactions
} // namespace Crypto
} // namespace Ark
#endif
/**
* This file is part of Ark Cpp Crypto.
*
* (c) Ark Ecosystem <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
**/
#include "transactions/deserializer.hpp"
#include <cstdbool>
#include <cstdint>
#include <utility>
#include <vector>
#include "interfaces/constants.h"
#include "transactions/defaults/offsets.hpp"
#include "transactions/transaction_data.hpp"
#include "utils/unpack.h"
namespace Ark {
namespace Crypto {
namespace transactions {
////////////////////////////////////////////////////////////////////////////////
// Deserialize Common
//
// @param TransactionData *data: The Transaction Data destination.
// @param const std::vector<uint8_t> &buffer
//
// ---
// Internals:
//
// Header - 1 Byte:
// - data->header = buffer.at(0);
//
// Transaction Version - 1 Byte:
// - data->version = buffer.at(1);
//
// Network Version - 1 Byte:
// - data->network = buffer.at(2);
//
// TypeGroup - 4 Bytes:
// - data->typeGroup = unpack4LE(&buffer, 3);
//
// Transaction Type - 2 Bytes:
// - data->type = unpack2LE(&buffer, 7);
//
// Nonce - 8 Bytes:
// - data->nonce = unpack8LE(&buffer, 9);
//
// SenderPublicKey - 33 Bytes:
// - std::move(&buffer.at(17), &buffer.at(50), data->senderPublicKey.begin());
//
// Fee - 8 bytes
// - data->fee = unpack8LE(&buffer, 50);
//
// VendorField Length - 1 Byte:
// - buffer.at(58);
//
// VendorField - 0 - 255 Bytes:
// - data->vendorField.insert(data->vendorField.begin(), &buffer.at(59), &buffer.at(59 + data->vendorField.size()));
//
// ---
static void deserializeCommon(TransactionData *data,
const std::vector<uint8_t> &buffer) {
data->header = buffer.at(HEADER_OFFSET); // 1 Byte
data->version = buffer.at(VERSION_OFFSET); // 1 Byte
data->network = buffer.at(NETWORK_OFFSET); // 1 Byte
data->typeGroup = unpack4LE(buffer, TYPEGROUP_OFFSET); // 4 Bytes
data->type = unpack2LE(buffer, TYPE_OFFSET); // 2 Bytes
data->nonce = unpack8LE(buffer, NONCE_OFFSET); // 8 Bytes
std::move(&buffer.at(SENDER_PUBLICKEY_OFFSET), // 21 Bytes
&buffer.at(SENDER_PUBLICKEY_OFFSET + PUBLICKEY_COMPRESSED_LEN),
data->senderPublicKey.begin());
data->fee = unpack8LE(buffer, FEE_OFFSET); // 8 Bytes
if (buffer.at(VF_LEN_OFFSET) != 0U) {
data->vendorField.insert( // 0 <=> 255 Bytes
data->vendorField.begin(),
&buffer.at(VF_OFFSET),
&buffer.at(VF_OFFSET + buffer.at(VF_LEN_OFFSET)));
};
}
////////////////////////////////////////////////////////////////////////////////
// Deserialize Common v1
//
// @param TransactionData *data: The Transaction Data destination.
// @param const std::vector<uint8_t> &buffer
//
// ---
// Internals:
//
// Header - 1 Byte:
// - data->header = buffer.at(0);
//
// Transaction Version - 1 Byte:
// - data->version = buffer.at(1);
//
// Network Version - 1 Byte:
// - data->network = buffer.at(2);
//
// Transaction Type - 1 Byte:
// - data->type = buffer.at(3);
//
// Timestamp - 4 Bytes
// - data->timestamp = unpack4LE(buffer, 4);
//
// SenderPublicKey - 33 Bytes:
// - std::move(&buffer.at(8), &buffer.at(41) data->senderPublicKey.begin());
//
// Fee - 8 bytes
// - data->fee = unpack8LE(buffer, 41);
//
// VendorField Length - 1 Byte:
// - buffer.at(49)
//
// VendorField - 0 - 255 Bytes:
// - data->vendorField.insert(data->vendorField.begin(), &buffer.at(50), &buffer.at(50 + buffer.at(49)));
//
// ---
static void deserializeCommonV1(TransactionData *data,
const std::vector<uint8_t> &buffer) {
data->header = buffer.at(HEADER_OFFSET); // 1 Byte
data->version = buffer.at(VERSION_OFFSET); // 1 Byte
data->network = buffer.at(NETWORK_OFFSET); // 1 Byte
data->type = buffer.at(v1::TYPE_OFFSET); // 1 Bytes
data->timestamp = unpack4LE(buffer, v1::TIMESTAMP_OFFSET); // 4 Bytes
std::move(&buffer.at(v1::SENDER_PUBLICKEY_OFFSET), // 33 Bytes
&buffer.at(v1::SENDER_PUBLICKEY_OFFSET + PUBLICKEY_COMPRESSED_LEN),
data->senderPublicKey.begin());
data->fee = unpack8LE(buffer, v1::FEE_OFFSET); // 8 Bytes
if (buffer.at(v1::VF_LEN_OFFSET) != 0U) {
data->vendorField.insert( // 0 <=> 255 Bytes
data->vendorField.begin(),
&buffer.at(v1::VF_OFFSET),
&buffer.at(v1::VF_OFFSET + buffer.at(v1::VF_LEN_OFFSET)));
};
}
////////////////////////////////////////////////////////////////////////////////
static auto deserializeAsset(TransactionData *transaction,
const std::vector<uint8_t> &buffer,
const size_t offset) -> size_t {
switch (transaction->type) {
case TRANSFER_TYPE:
return Transfer::Deserialize(
&transaction->asset.transfer,
&buffer.at(offset));
case SECOND_SIGNATURE_TYPE:
return SecondSignature::Deserialize(
&transaction->asset.secondSignature,
&buffer.at(offset));
case DELEGATE_REGISTRATION_TYPE:
return DelegateRegistration::Deserialize(
&transaction->asset.delegateRegistration,
&buffer.at(offset));
case VOTE_TYPE:
return Vote::Deserialize(
&transaction->asset.vote,
&buffer.at(offset));
// case MULTI_SIGNATURE_TYPE: // TODO
case IPFS_TYPE:
return Ipfs::Deserialize(
&transaction->asset.ipfs,
&buffer.at(offset));
case MULTI_PAYMENT_TYPE:
return MultiPayment::Deserialize(
&transaction->asset.multiPayment,
&buffer.at(offset));
case DELEGATE_RESIGNATION_TYPE: return 0UL;
case HTLC_LOCK_TYPE:
return HtlcLock::Deserialize(
&transaction->asset.htlcLock,
&buffer.at(offset));
case HTLC_CLAIM_TYPE:
return HtlcClaim::Deserialize(
&transaction->asset.htlcClaim,
&buffer.at(offset));
case HTLC_REFUND_TYPE:
return HtlcRefund::Deserialize(
&transaction->asset.htlcRefund,
&buffer.at(offset));
case SCOOTER_TYPE:
if (transaction->typeGroup == SCOOTER_TYPEGROUP) {
return ScooterRegistration::Deserialize(
&transaction->asset.scooterRegistration,
&buffer.at(offset));
}
default: return 0UL;
};
}
////////////////////////////////////////////////////////////////////////////////
static void deserializeSignatures(TransactionData *transaction,
const uint8_t *buffer) {
uint8_t signatureLength = buffer[1] + 2U;
if (signatureLength >= SIGNATURE_ECDSA_MIN &&
signatureLength <= SIGNATURE_ECDSA_MAX) {
transaction->signature.reserve(SIGNATURE_ECDSA_MAX);
transaction->signature.insert(transaction->signature.begin(),
buffer,
buffer + signatureLength);
}
uint8_t secondSignatureLength = buffer[signatureLength + 1U] + 2U;
if (secondSignatureLength >= SIGNATURE_ECDSA_MIN &&
secondSignatureLength <= SIGNATURE_ECDSA_MAX) {
transaction->secondSignature.reserve(SIGNATURE_ECDSA_MAX);
transaction->secondSignature.insert(
transaction->secondSignature.begin(),
buffer + signatureLength,
buffer + signatureLength + secondSignatureLength);
}
}
////////////////////////////////////////////////////////////////////////////////
// Deserialize Transaction Data
//
// @param TransactionData *data
// @param const std::vector<uint8_t> &buffer
//
// ---
auto Deserializer::deserialize(TransactionData *data,
const std::vector<uint8_t> &buffer) -> bool {
size_t assetOffset = 0UL;
// Use v2 or v1, otherwise return with no changes to the Tx Data.
if (buffer.at(VERSION_OFFSET) == 0x02) {
deserializeCommon(data, buffer);
assetOffset = VF_OFFSET + data->vendorField.size();
}
else if(buffer.at(VERSION_OFFSET) == 0x01) {
deserializeCommonV1(data, buffer);
assetOffset = v1::VF_OFFSET + data->vendorField.size();
}
else { return false; }
size_t assetSize = deserializeAsset(data, buffer, assetOffset);
deserializeSignatures(data, &buffer[assetOffset + assetSize]);
return true;
}
} // namespace transactions
} // namespace Crypto
} // namespace Ark
/**
* This file is part of Ark Cpp Crypto.
*
* (c) Ark Ecosystem <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
**/
#include "transactions/serializer.hpp"
#include <cstdint>
#include <cstring>
#include <vector>
#include "interfaces/constants.h"
#include "crypto/hash.hpp"
#include "transactions/defaults/offsets.hpp"
#include "transactions/transaction_data.hpp"
namespace Ark {
namespace Crypto {
namespace transactions {
////////////////////////////////////////////////////////////////////////////////
// Serialize Common
//
// @param const TransactionData &data
// @param std::vector<uint8_t> &buffer: The serialized transactions buffer.
//
// ---
// Internals:
//
// Header - 1 Byte:
// - buffer.at(0) = transaction.header;
//
// Transaction Version - 1 Byte:
// - buffer.at(1) = transaction.version;
//
// Network Version - 1 Byte:
// - buffer.at(2) = transaction.network;
//
// TypeGroup - 4 Bytes:
// - memmove(&buffer.at(3), &transaction.typeGroup, sizeof(uint32_t));
//
// Transaction Type - 2 Bytes:
// - memmove(&buffer.at(7), &transaction.type, sizeof(uint16_t));
//
// Nonce - 8 Bytes:
// - memmove(&buffer.at(9), &transaction.nonce, sizeof(uint64_t));
//
// SenderPublicKey - 33 Bytes:
// - buffer.insert(buffer.begin() + 17, transaction.senderPublicKey.begin(), transaction.senderPublicKey.end());
//
// Fee - 8 bytes
// - memmove(&buffer.at(50), &transaction.fee, sizeof(uint64_t));
//
// VendorField Length - 1 Byte:
// - buffer.at(58) = transaction.vendorField.size();
//
// VendorField - 0 <=> 255 Bytes:
// - buffer.insert(buffer.begin() + 59, transaction.vendorField.begin(), transaction.vendorField.end());
//
// ---
static void serializeCommon(const TransactionData &transaction,
std::vector<uint8_t> &buffer) {
buffer.at(HEADER_OFFSET) = transaction.header; // 1 Byte
buffer.at(VERSION_OFFSET) = transaction.version; // 1 Byte
buffer.at(NETWORK_OFFSET) = transaction.network; // 1 Byte
memmove(&buffer.at(TYPEGROUP_OFFSET), // 4 Bytes
&transaction.typeGroup,
sizeof(uint32_t));
memmove(&buffer.at(TYPE_OFFSET), // 2 Bytes
&transaction.type,
sizeof(uint16_t));
memmove(&buffer.at(NONCE_OFFSET), // 4 Bytes
&transaction.nonce,
sizeof(uint64_t));
buffer.insert(buffer.begin() + SENDER_PUBLICKEY_OFFSET, // 21 Bytes
transaction.senderPublicKey.begin(),
transaction.senderPublicKey.end());
memmove(&buffer.at(FEE_OFFSET), // 8 Bytes
&transaction.fee,
sizeof(uint64_t));
buffer.at(VF_LEN_OFFSET) = // 1 Byte
static_cast<uint8_t>(transaction.vendorField.size());
if (!transaction.vendorField.empty()) {
buffer.insert(buffer.begin() + VF_OFFSET, // 0 <=> 255 Bytes
transaction.vendorField.begin(),
transaction.vendorField.end());
}
}
////////////////////////////////////////////////////////////////////////////////
// Serialize Common V1
//
// @param const TransactionData &data
// @param std::vector<uint8_t> &buffer: The serialized transactions buffer.
//
// ---
// Internals:
//
// Header - 1 Byte:
// - buffer.at(0) = transaction.header;
//
// Transaction Version - 1 Byte:
// - buffer.at(1) = transaction.version;
//
// Network Version - 1 Byte:
// - buffer.at(2) = transaction.network;
//
// Transaction Type - 1 Byte:
// - buffer.at(3) = transaction.type;
//
// Timestamp - 4 Bytes
// - memmove(&buffer.at(4), &transaction.timestamp,sizeof(uint32_t));
//
// SenderPublicKey - 33 Bytes:
// - buffer.insert(buffer.begin() + 8, transaction.senderPublicKey.begin(), transaction.senderPublicKey.end());
//
// Fee - 8 bytes
// - memmove(&buffer.at(41), &transaction.fee, sizeof(uint64_t));
//
// VendorField Length - 1 Byte:
// - buffer.at(49) = transaction.vendorField.size();
//
// VendorField - 0 <=> 255 Bytes:
// - buffer.insert(buffer.begin() + 50, transaction.vendorField.begin(), transaction.vendorField.end());
//
// ---
static void serializeCommonV1(const TransactionData &transaction,
std::vector<uint8_t> &buffer) {
buffer.at(v1::HEADER_OFFSET) = transaction.header; // 1 Byte
buffer.at(v1::VERSION_OFFSET) = transaction.version; // 1 Byte
buffer.at(v1::NETWORK_OFFSET) = transaction.network; // 1 Byte
buffer.at(v1::TYPE_OFFSET) = // 1 Byte
static_cast<uint8_t>(transaction.type);
memmove(&buffer.at(v1::TIMESTAMP_OFFSET), // 4 Bytes
&transaction.timestamp,
sizeof(uint32_t));
buffer.insert(buffer.begin() + v1::SENDER_PUBLICKEY_OFFSET, // 21 Bytes
transaction.senderPublicKey.begin(),
transaction.senderPublicKey.end());
memmove(&buffer.at(v1::FEE_OFFSET), // 8 Bytes
&transaction.fee,
sizeof(uint64_t));
buffer.at(v1::VF_LEN_OFFSET) = // 1 Byte
static_cast<uint8_t>(transaction.vendorField.size());
if (!transaction.vendorField.empty()) {
buffer.insert(buffer.begin() + v1::VF_OFFSET, // 0 <=> 255 Bytes
transaction.vendorField.begin(),
transaction.vendorField.end());
}
}
////////////////////////////////////////////////////////////////////////////////
static auto serializeAsset(const TransactionData &transaction,
std::vector<uint8_t> &buffer,
const size_t offset) -> size_t {
switch (transaction.type) {
case TRANSFER_TYPE:
return Transfer::Serialize(
transaction.asset.transfer,
&buffer.at(offset));
case SECOND_SIGNATURE_TYPE:
return SecondSignature::Serialize(
transaction.asset.secondSignature,
&buffer.at(offset));
case DELEGATE_REGISTRATION_TYPE:
return DelegateRegistration::Serialize(
transaction.asset.delegateRegistration,
&buffer.at(offset));
case VOTE_TYPE:
return Vote::Serialize(
transaction.asset.vote,
&buffer.at(offset));
// case MULTI_SIGNATURE_TYPE: // TODO
case IPFS_TYPE:
return Ipfs::Serialize(
transaction.asset.ipfs,
&buffer.at(offset));
case MULTI_PAYMENT_TYPE:
return MultiPayment::Serialize(
transaction.asset.multiPayment,
buffer,
offset);
case DELEGATE_RESIGNATION_TYPE: return 0UL;
case HTLC_LOCK_TYPE:
return HtlcLock::Serialize(
transaction.asset.htlcLock,
&buffer.at(offset));
case HTLC_CLAIM_TYPE:
return HtlcClaim::Serialize(
transaction.asset.htlcClaim,
&buffer.at(offset));
case HTLC_REFUND_TYPE:
return HtlcRefund::Serialize(
transaction.asset.htlcRefund,
&buffer.at(offset));
case SCOOTER_TYPE:
if (transaction.typeGroup == SCOOTER_TYPEGROUP) {
return ScooterRegistration::Serialize(
transaction.asset.scooterRegistration,
&buffer.at(offset));
}
default: return 0UL;
};
}
////////////////////////////////////////////////////////////////////////////////
static auto serializeSignatures(const TransactionData &data,
std::vector<uint8_t> &buffer,
const size_t offset,
const SerializerOptions &options) -> size_t {
if (!options.excludeSignature &&
data.signature.size() >= SIGNATURE_ECDSA_MIN &&
data.signature.size() <= SIGNATURE_ECDSA_MAX) {
buffer.insert(buffer.begin() + offset,
data.signature.begin(),
data.signature.end());
}
else { return 0UL; }
if (!options.excludeSecondSignature &&
data.secondSignature.size() >= SIGNATURE_ECDSA_MIN &&
data.secondSignature.size() <= SIGNATURE_ECDSA_MAX) {
buffer.insert(buffer.begin() + offset + data.signature.size(),
data.secondSignature.begin(),
data.secondSignature.end());
}
else { return data.signature.size(); }
return data.signature.size() + data.secondSignature.size();
}
////////////////////////////////////////////////////////////////////////////////
// Serialize Transaction Data
//
// @param const TransactionData &data
// @param const SerializerOptions &options
//
// @return std::vector<uint8_t>
//
// ---
auto Serializer::serialize(const TransactionData &data,
const SerializerOptions &options)
-> std::vector<uint8_t>{
std::vector<uint8_t> buffer;
buffer.resize(TX_DEFAULT_SIZE);
size_t assetOffset = 0UL;
// Use v2 or v1, otherwise return an empty object.
if (data.version == TRANSACTION_VERSION_TYPE_2) {
serializeCommon(data, buffer);
assetOffset = VF_OFFSET + data.vendorField.size();
}
else if (data.version == TRANSACTION_VERSION_TYPE_1) {
serializeCommonV1(data, buffer);
assetOffset = v1::VF_OFFSET + data.vendorField.size();
}
else { return {}; }
size_t assetSize = serializeAsset(data, buffer, assetOffset);
size_t signaturesSize = serializeSignatures(data,
buffer,
assetOffset + assetSize,
options);
buffer.resize(assetOffset + assetSize + signaturesSize);
return buffer;
}
} // namespace transactions
} // namespace Crypto
} // namespace Ark
/**
* This file is part of Ark Cpp Crypto.
*
* (c) Ark Ecosystem <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
**/
#include "transactions/transaction.hpp"
#include <cstddef>
#include <cstdint>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "crypto/curve.hpp"
#include "crypto/hash.hpp"
#include "identities/keys.hpp"
#include "transactions/deserializer.hpp"
#include "transactions/serializer.hpp"
#include "transactions/defaults/offsets.hpp"
#include "transactions/transaction_data.hpp"
#include "utils/base58.hpp"
#include "utils/hex.hpp"
#include "utils/json.h"
#include "utils/str.hpp"
namespace Ark {
namespace Crypto {
namespace transactions {
////////////////////////////////////////////////////////////////////////////////
// Compute the unique transaction ID.
auto Transaction::getId() const -> Hash32 {
const auto serialized = this->toBytes(false, false);
return Hash::sha256(serialized.data(), serialized.size());
}
////////////////////////////////////////////////////////////////////////////////
// Sign the transaction using a passphrase.
auto Transaction::sign(const std::string &passphrase) -> bool {
if (passphrase.empty()) {
return false;
}
const auto keys = identities::Keys::fromPassphrase(passphrase.c_str());
std::move(keys.publicKey.begin(),
keys.publicKey.end(),
this->data.senderPublicKey.begin());
const auto serialized = this->toBytes(true, true);
const auto hash32 = Hash::sha256(serialized.data(), serialized.size());
this->data.signature.reserve(SIGNATURE_ECDSA_MAX);
return Curve::Ecdsa::sign(hash32.data(),
keys.privateKey.data(),
&this->data.signature);
}
////////////////////////////////////////////////////////////////////////////////
// Sign the Transaction using a Second Passphrase.
auto Transaction::secondSign(const std::string &secondPassphrase) -> bool {
if (this->data.signature.empty() || secondPassphrase.empty()) {
return false;
}
const auto keys = identities::Keys::fromPassphrase(secondPassphrase.c_str());
const auto serialized = this->toBytes(false, true);
const auto hash32 = Hash::sha256(serialized.data(), serialized.size());
this->data.secondSignature.reserve(SIGNATURE_ECDSA_MAX);
return Curve::Ecdsa::sign(hash32.data(),
keys.privateKey.data(),
&this->data.secondSignature);
}
////////////////////////////////////////////////////////////////////////////////
// Verify the Transaction.
auto Transaction::verify() const -> bool {
// skip both signatures,
// neither should be present in the signing hash.
const auto serialized = this->toBytes(true, true);
const auto hash32 = Hash::sha256(serialized.data(), serialized.size());
return Curve::Ecdsa::verify(hash32.data(),
this->data.senderPublicKey.data(),
this->data.signature);
}
////////////////////////////////////////////////////////////////////////////////
// Verify the Transaction using a Second PublicKey.
auto Transaction::secondVerify(const uint8_t *secondPublicKey) const -> bool {
// include only the first signature,
// that should be present signing hash for a second signing.
const auto serialized = this->toBytes(false, true);
const auto hash32 = Hash::sha256(serialized.data(), serialized.size());
return Curve::Ecdsa::verify(hash32.data(),
secondPublicKey,
this->data.secondSignature);
}
////////////////////////////////////////////////////////////////////////////////
// Deserialize the given Hex string via AIP11.
auto Transaction::deserialize(const std::vector<uint8_t> &serialized) -> bool {
return Deserializer::deserialize(&this->data, serialized);
}
////////////////////////////////////////////////////////////////////////////////
// Serialize the object via AIP11.
auto Transaction::serialize() -> std::vector<uint8_t> {
return Serializer::serialize(this->data);
}
////////////////////////////////////////////////////////////////////////////////
// Turn the Transaction into its byte representation.
auto Transaction::toBytes(bool excludeSignature,
bool excludeSecondSignature) const
-> std::vector<uint8_t> {
return Serializer::serialize(this->data,
{ excludeSignature, excludeSecondSignature });
}
////////////////////////////////////////////////////////////////////////////////
// Turn the transaction into a standardized array.
//
// This concept of an array in is quite different compared to other ARK SDKs.
// C++11 doesn't have an 'Any' type, so we'll need to use a string map here.
//
// Json Sizes are approximated using 'https://arduinojson.org/v6/assistant/'
//
// --
auto Transaction::toMap() const -> std::map<std::string, std::string> {
std::map<std::string, std::string> map;
size_t jsonSize = 0UL;
size_t extraBytes =
static_cast<size_t>(this->data.vendorField.empty()) +
this->data.vendorField.size() + sizeof("vendorField") - 1 +
static_cast<size_t>(this->data.signature.empty()) +
this->data.signature.size() + sizeof("signature") - 1 +
static_cast<size_t>(this->data.secondSignature.empty()) +
this->data.secondSignature.size() + sizeof("secondSignature") - 1;
// Start with the Transaction's Asset.
// Tranfer
if (this->data.type == TRANSFER_TYPE) {
map = Transfer::getMap(this->data.asset.transfer);
jsonSize = JSON_OBJECT_SIZE(11) +
TRANSACTION_TYPE_TRANSFER_SIZE +
extraBytes +
289;
}
// Second Signature Registration
if (this->data.type == SECOND_SIGNATURE_TYPE) {
map = SecondSignature::getMap(this->data.asset.secondSignature);
jsonSize = 2 * JSON_OBJECT_SIZE(1) +
JSON_OBJECT_SIZE(9) +
PUBLICKEY_COMPRESSED_LEN +
extraBytes +
297;
}
// Delegate Registration
if (this->data.type == DELEGATE_REGISTRATION_TYPE) {
map = DelegateRegistration::getMap(
this->data.asset.delegateRegistration);
jsonSize =
2 * JSON_OBJECT_SIZE(1) +
JSON_OBJECT_SIZE(9) +
sizeof("username") - 1 +
strtol(map["usernameLen"].c_str(), nullptr, BASE_10) +
extraBytes +
251;
}
// Vote
if (this->data.type == VOTE_TYPE) {
map = Vote::getMap(this->data.asset.vote);
jsonSize = JSON_ARRAY_SIZE(1) +
JSON_OBJECT_SIZE(1) +
JSON_OBJECT_SIZE(9) +
VOTES_LEN +
extraBytes +
284;
}
// MultiSignature Registration
// if (this->data.type == MULTI_SIGNATURE_TYPE) {} // TODO
// Ipfs
if (this->data.type == IPFS_TYPE) {
map = Ipfs::getMap(this->data.asset.ipfs);
jsonSize = 2 * JSON_OBJECT_SIZE(1) +
JSON_OBJECT_SIZE(11) +
strtol(map["ipfsLen"].c_str(), nullptr, BASE_10) +
sizeof("ipfs") - 1U +
extraBytes +
218;
}
// MultiPayment
if (this->data.type == MULTI_PAYMENT_TYPE) {
map = MultiPayment::getMap(this->data.asset.multiPayment);
// Get the number of payments.
const auto n_payments = strtol(map["n_payments"].c_str(),
nullptr,
BASE_10);
const auto uint64StrSize = 20;
jsonSize =
JSON_ARRAY_SIZE(n_payments) +
JSON_OBJECT_SIZE(1) +
(n_payments * JSON_OBJECT_SIZE(2)) +
JSON_OBJECT_SIZE(10) +
(n_payments * (sizeof("amount") - 1 + uint64StrSize +
sizeof("recipientId") - 1 + ADDRESS_STR_LEN)) +
483;
}
// Delegate Resignation
if (this->data.type == DELEGATE_RESIGNATION_TYPE) {
jsonSize = JSON_OBJECT_SIZE(10) + extraBytes * 205;
}
// Htlc Lock
if (this->data.type == HTLC_LOCK_TYPE) {
map = HtlcLock::getMap(this->data.asset.htlcLock);
jsonSize = JSON_OBJECT_SIZE(1) +
(2 * JSON_OBJECT_SIZE(2)) +
JSON_OBJECT_SIZE(11) +
HTLC_LOCK_SIZE +
extraBytes +
368;
}
// Htlc Claim
if (this->data.type == HTLC_CLAIM_TYPE) {
map = HtlcClaim::getMap(this->data.asset.htlcClaim);
jsonSize = JSON_OBJECT_SIZE(1) +
JSON_OBJECT_SIZE(2) +
JSON_OBJECT_SIZE(9) +
HASH_32_LEN + HASH_32_LEN +
extraBytes +
337;
}
// Htlc Refund
if (this->data.type == HTLC_REFUND_TYPE) {
map = HtlcRefund::getMap(this->data.asset.htlcRefund);
jsonSize = 2 * JSON_OBJECT_SIZE(1) +
JSON_OBJECT_SIZE(11) +
HASH_32_LEN +
extraBytes +
445;
}
// Scooter Registration
if (this->data.typeGroup == SCOOTER_TYPEGROUP && this->data.type == SCOOTER_TYPE) {
map = ScooterRegistration::getMap(this->data.asset.scooterRegistration);
jsonSize = 2 * JSON_OBJECT_SIZE(1) +
JSON_OBJECT_SIZE(9) +
sizeof("scooterId") - 1 + SCOOTER_ID_LEN +
extraBytes +
233;
}
// Continue with the Common variables
// Version
map.emplace("version", UintToString(this->data.version));
// Network
map.emplace("network", UintToString(this->data.network));
// v2
if (this->data.version == TRANSACTION_VERSION_TYPE_2) {
// TypeGroup
map.emplace("typeGroup", UintToString(this->data.typeGroup));
}
// Type
map.emplace("type", UintToString(this->data.type));
// v2
if (this->data.version == TRANSACTION_VERSION_TYPE_2) {
// Nonce
map.emplace("nonce", UintToString(this->data.nonce));
}
// v1
else if (this->data.version == TRANSACTION_VERSION_TYPE_1) {
// Timestamp
map.emplace("timestamp", UintToString(this->data.timestamp));
}
// Sender PublicKey
map.emplace("senderPublicKey", BytesToHex(this->data.senderPublicKey));
// Fee
map.emplace("fee", UintToString(this->data.fee));
// VendorField
if (!this->data.vendorField.empty()) {
const auto vf = reinterpret_cast<const char *>(
this->data.vendorField.data());
map.emplace("vendorField",
std::string(vf, vf + this->data.vendorField.size()));
}
// Signature
if (!this->data.signature.empty()) {
map.emplace("signature", BytesToHex(this->data.signature));
}
// Second Signature
if (!this->data.secondSignature.empty()) {
map.emplace("secondSignature", BytesToHex(this->data.secondSignature));
}
// Transaction Id
map.emplace("id", BytesToHex(this->getId()));
// v2
if (this->data.version == TRANSACTION_VERSION_TYPE_2) {
jsonSize += VF_OFFSET;
}
// v1
else if (this->data.version == TRANSACTION_VERSION_TYPE_1) {
jsonSize += v1::VF_OFFSET;
}
map.emplace("jsonSize", UintToString(jsonSize));
return map;
}
////////////////////////////////////////////////////////////////////////////////
// Turn the Transaction into a JSON string using `toMap` as the source.
auto Transaction::toJson() const -> std::string {
auto txArray = this->toMap();
const auto jsonSize = strtol(txArray["jsonSize"].c_str(), nullptr, BASE_10);
const auto docCapacity = jsonSize;
DynamicJsonDocument doc(docCapacity);
// Version
doc["version"] = strtol(txArray["version"].c_str(), nullptr, BASE_10);
// Network
doc["network"] = strtol(txArray["network"].c_str(), nullptr, BASE_10);
// v2
if (this->data.version == TRANSACTION_VERSION_TYPE_2) {
// TypeGroup
doc["typeGroup"] = strtol(txArray["typeGroup"].c_str(),
nullptr,
BASE_10);
}
// Type
doc["type"] = strtol(txArray["type"].c_str(), nullptr, BASE_10);
// v2
if (this->data.version == TRANSACTION_VERSION_TYPE_2) {
// Nonce
doc["nonce"] = txArray["nonce"];
}
// v1
else if (this->data.version == TRANSACTION_VERSION_TYPE_1) {
// Timestamp
doc["timestamp"] = txArray["timestamp"];
}
// Sender PublicKey
doc["senderPublicKey"] = txArray["senderPublicKey"];
// Fee
doc["fee"] = txArray["fee"];
// VendorField
if (!this->data.vendorField.empty()) {
doc["vendorField"] = txArray["vendorField"];
}
// Assets
// Transfer
if (this->data.type == TRANSFER_TYPE) {
// Amount
doc["amount"] = txArray["amount"];
// Expiration
doc["expiration"] = strtol(txArray["expiration"].c_str(),
nullptr,
BASE_10);
// RecipientId
doc["recipientId"] = txArray["recipientId"];
}
// Second Signature Registration
if (this->data.type == SECOND_SIGNATURE_TYPE) {
JsonObject asset = doc.createNestedObject("asset");
JsonObject secondSignature = asset.createNestedObject("signature");
// Second PublicKey
secondSignature["publicKey"] = txArray["publicKey"];
}
// Delegate Registration
if (this->data.type == DELEGATE_REGISTRATION_TYPE) {
JsonObject asset = doc.createNestedObject("asset");
JsonObject registration = asset.createNestedObject("delegate");
// Username
registration["username"] = txArray["username"];
}
// Vote
if (this->data.type == VOTE_TYPE) {
JsonObject asset = doc.createNestedObject("asset");
JsonArray votes = asset.createNestedArray("votes");
// Votes
votes.add(txArray["votes"]);
}
// MultiSignature Registration
// if (this->data.type == MULTI_SIGNATURE_TYPE) {} // TODO
// Ipfs
if (this->data.type == IPFS_TYPE) {
JsonObject asset = doc.createNestedObject("asset");
// Ipfs DAG
asset["ipfs"] = txArray["ipfs"];
}
// MultiPayment
if (this->data.type == MULTI_PAYMENT_TYPE) {
JsonObject asset = doc.createNestedObject("asset");
JsonArray payments = asset.createNestedArray("payments");
const auto paymentsStr = txArray["amounts"];
const auto addressesStr = txArray["addresses"];
const auto n_payments = strtol(txArray["n_payments"].c_str(),
nullptr,
BASE_10);
for (uint8_t i = 0U; i < n_payments; ++i) {
JsonObject payment_n = payments.createNestedObject();
// Ammount(N)
payment_n["amount"] = paymentsStr
.substr(0, paymentsStr.find(',', 0));
// RecipientId(N)
payment_n["recipientId"] = addressesStr
.substr(i + (i * ADDRESS_STR_LEN), ADDRESS_STR_LEN);
}
}
// Delegate Resignation
// No Asset Needed.
// HTLC Lock
if (this->data.type == HTLC_LOCK_TYPE) {
// Amount
doc["amount"] = txArray["amount"];
// RecipientId
doc["recipientId"] = txArray["recipientId"];
JsonObject asset = doc.createNestedObject("asset");
JsonObject lock = asset.createNestedObject("lock");
// Secret Hash
lock["secretHash"] = txArray["secretHash"];
JsonObject expiration = lock.createNestedObject("expiration");
// Expiration Type
expiration["type"] = strtol(txArray["expirationType"].c_str(),
nullptr,
BASE_10);
// Expiration Value
expiration["value"] = strtol(txArray["expiration"].c_str(),
nullptr,
BASE_10);
}
// HTLC Claim
if (this->data.type == HTLC_CLAIM_TYPE) {
JsonObject asset = doc.createNestedObject("asset");
JsonObject claim = asset.createNestedObject("claim");
// Lock Transaction Id
claim["lockTransactionId"] = txArray["lockTransactionId"];
// Unlock Secret
claim["unlockSecret"] = txArray["unlockSecret"];
}
// HTLC Refund
if (this->data.type == HTLC_REFUND_TYPE) {
JsonObject asset = doc.createNestedObject("asset");
JsonObject refund = asset.createNestedObject("refund");
// Lock Transaction Id
refund["lockTransactionId"] = txArray["lockTransactionId"];
}
// Scooter Registration
if (this->data.typeGroup == SCOOTER_TYPEGROUP && this->data.type == SCOOTER_TYPE) {
doc["amount"] = "0";
JsonObject asset = doc.createNestedObject("asset");
// ScooterId
asset["scooterId"] = txArray["scooterId"];
}
// Signature
if (!this->data.signature.empty()) {
doc["signature"] = txArray["signature"];
}
// Second Signature
if (!this->data.secondSignature.empty()) {
doc["secondSignature"] = txArray["secondSignature"];
}
// Transaction Id
doc["id"] = txArray["id"];
std::string jsonStr;
jsonStr.reserve(docCapacity);
serializeJson(doc, jsonStr);
return jsonStr;
}
} // namespace transactions
} // namespace Crypto
} // namespace Ark
/**
* This file is part of Ark Cpp Crypto.
*
* (c) Ark Ecosystem <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
**/
#ifndef ARK_TRANSACTIONS_TYPES_ASSETS_HPP
#define ARK_TRANSACTIONS_TYPES_ASSETS_HPP
#include "transactions/defaults/types.hpp"
#include "transactions/types/transfer.hpp"
#include "transactions/types/second_signature.hpp"
#include "transactions/types/delegate_registration.hpp"
#include "transactions/types/vote.hpp"
// #include "transactions/types/multi_signature.hpp"
#include "transactions/types/ipfs.hpp"
#include "transactions/types/multi_payment.hpp"
#include "transactions/types/delegate_resignation.hpp"
#include "transactions/types/htlc_lock.hpp"
#include "transactions/types/htlc_claim.hpp"
#include "transactions/types/htlc_refund.hpp"
#include "transactions/types/scooter_registration.hpp"
namespace Ark {
namespace Crypto {
namespace transactions {
////////////////////////////////////////////////////////////////////////////////
// AIP-11 Transaction Assets
typedef struct tx_asset_t {
Transfer transfer; // Type 0
SecondSignature secondSignature; // Type 1
DelegateRegistration delegateRegistration; // Type 2
Vote vote; // Type 3
// MultiSignature multiSignature; // Type 4
Ipfs ipfs; // Type 5
MultiPayment multiPayment; // Type 6
DelegateResignation delegateResignation; // Type 7
HtlcLock htlcLock; // Type 8
HtlcClaim htlcClaim; // Type 9
HtlcRefund htlcRefund; // Type 10
ScooterRegistration scooterRegistration; // TypeGroup 4000, type 400
} Asset;
} // namespace transactions
} // namespace Crypto
} // namespace Ark
#endif
/**
* This file is part of Ark Cpp Crypto.
*
* (c) Ark Ecosystem <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
**/
#include "transactions/types/scooter_registration.hpp"
#include <cstdint>
#include <map>
#include <string>
#include <utility>
namespace Ark {
namespace Crypto {
namespace transactions {
////////////////////////////////////////////////////////////////////////////////
// Deserialize Scooter Registration (TypeGroup 4000, Type 400) - 11 bytes
//
// @param ScooterRegistration *registration
// @param uint8_t *buffer: The serialized buffer beginning at the Assets offset.
//
// @return Asset Length
//
// ---
// Internals:
//
// ScooterId Len - 1 Byte
// - registration->scooterId.resize(buffer[0]);
//
// ScooterId - 10 Bytes:
// - std::move(&buffer[1], &buffer[1 + 10], registration->scooterId.data());
//
// ---
auto ScooterRegistration::Deserialize(ScooterRegistration *registration,
const uint8_t *buffer)
-> size_t {
registration->scooterId.resize(buffer[0]); // 1 Byte
std::move(&buffer[sizeof(uint8_t)], // 10 Bytes
&buffer[sizeof(uint8_t) + SCOOTER_ID_LEN],
registration->scooterId.begin());
return sizeof(uint8_t) + SCOOTER_ID_LEN; // 11 Bytes
}
////////////////////////////////////////////////////////////////////////////////
// Serialize Scooter Registration (TypeGroup 4000, Type 400) - 11 bytes
//
// @param const ScooterRegistration &registration
// @param uint8_t *buffer: The serialized buffer at the Assets offset.
//
// @return Asset Length
//
// ---
// Internals:
//
// ScooterId Length - 1 Byte
// - buffer[0] = static_cast<uint8_t>(10);
//
// ScooterId - 10 Bytes:
// - std::move(registration.scooterId.begin(), registration.scooterId.end(), &buffer[1]);
//
// ---
auto ScooterRegistration::Serialize(const ScooterRegistration &registration,
uint8_t *buffer) -> size_t {
buffer[0] = // 1 Byte
static_cast<uint8_t>(registration.scooterId.length());
std::move(registration.scooterId.begin(), // 10 Bytes
registration.scooterId.end(),
&buffer[sizeof(uint8_t)]);
return sizeof(uint8_t) + SCOOTER_ID_LEN; // 11 Bytes
}
////////////////////////////////////////////////////////////////////////////////
// Return a Map of the Transfer asset.
auto ScooterRegistration::getMap(const ScooterRegistration &registration)
-> std::map<std::string, std::string> {
std::map<std::string, std::string> map;
// ScooterId
map.emplace("scooterId", registration.scooterId);
return map;
}
} // namespace transactions
} // namespace Crypto
} // namespace Ark
/**
* This file is part of Ark Cpp Crypto.
*
* (c) Ark Ecosystem <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
**/
#ifndef ARK_TRANSACTIONS_TYPES_SCOOTER_REGISTRATION_HPP
#define ARK_TRANSACTIONS_TYPES_SCOOTER_REGISTRATION_HPP
#include <array>
#include <cstdint>
#include <cstring>
#include <map>
#include <string>
#include "interfaces/constants.h"
#include "utils/json.h"
namespace Ark {
namespace Crypto {
namespace transactions {
const uint32_t SCOOTER_TYPEGROUP = 4000UL;
const uint16_t SCOOTER_TYPE = 400UL;
const size_t SCOOTER_ID_LEN = 10UL;
////////////////////////////////////////////////////////////////////////////////
// TypeGroup 4000, Type 400 - Scooter Registration
struct ScooterRegistration {
////////////////////////////////////////////////////////////////////////////
std::string scooterId;
////////////////////////////////////////////////////////////////////////////
static size_t Deserialize(ScooterRegistration *registration,
const uint8_t *buffer);
////////////////////////////////////////////////////////////////////////////
static size_t Serialize(const ScooterRegistration &registration,
uint8_t *buffer);
////////////////////////////////////////////////////////////////////////////
static std::map<std::string, std::string> getMap(
const ScooterRegistration &registration);
////////////////////////////////////////////////////////////////////////////
ScooterRegistration() : scooterId() {}
};
} // namespace transactions
} // namespace Crypto
} // namespace Ark
#endif
cmake_minimum_required(VERSION 3.2)
project(${PROJECT_NAME}_tests C CXX)
set (PROJECT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../lib")
# ------------------------------------------------------------------------------
# External Libraries
# ------------------------------------------------------------------------------
include(${CMAKE_SOURCE_DIR}/cmake/GTest.cmake)
include_directories(${ARDUINO_JSON_SOURCE_DIR})
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Link the directories to be included
# ------------------------------------------------------------------------------
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR}/../src)
include_directories(${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# ARK C++ Crypto Test Source
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Common
set(COMMON_TEST_SOURCE
${PROJECT_SOURCE_DIR}/common/configuration.cpp
${PROJECT_SOURCE_DIR}/common/fee_policy.cpp
${PROJECT_SOURCE_DIR}/common/network.cpp
)
# ------------------------------------------------------------------------------
# Crypto
set(CRYPTO_TEST_SOURCE
${PROJECT_SOURCE_DIR}/crypto/curve_ecdsa_sign_null_hash.cpp
${PROJECT_SOURCE_DIR}/crypto/curve_ecdsa_sign_null_privatekey.cpp
${PROJECT_SOURCE_DIR}/crypto/curve_ecdsa_sign.cpp
${PROJECT_SOURCE_DIR}/crypto/curve_publickey.cpp
${PROJECT_SOURCE_DIR}/crypto/curve_verify_invalid.cpp
${PROJECT_SOURCE_DIR}/crypto/curve_verify_valid.cpp
${PROJECT_SOURCE_DIR}/crypto/hash.cpp
${PROJECT_SOURCE_DIR}/crypto/message_sign.cpp
${PROJECT_SOURCE_DIR}/crypto/message_verify.cpp
${PROJECT_SOURCE_DIR}/crypto/message.cpp
${PROJECT_SOURCE_DIR}/crypto/slot.cpp
)
# ------------------------------------------------------------------------------
# Identities
set(IDENTITIES_TEST_SOURCE
${PROJECT_SOURCE_DIR}/identities/address.cpp
${PROJECT_SOURCE_DIR}/identities/keys.cpp
${PROJECT_SOURCE_DIR}/identities/keys_publickey.cpp
${PROJECT_SOURCE_DIR}/identities/privatekey.cpp
${PROJECT_SOURCE_DIR}/identities/publickey.cpp
${PROJECT_SOURCE_DIR}/identities/wif.cpp
)
# ------------------------------------------------------------------------------
# Managers
set(MANAGERS_TEST_SOURCE
${PROJECT_SOURCE_DIR}/managers/fee_manager.cpp
${PROJECT_SOURCE_DIR}/managers/network_manager.cpp
)
# ------------------------------------------------------------------------------
# Networks
set(NETWORKS_TEST_SOURCE
${PROJECT_SOURCE_DIR}/networks/devnet.cpp
${PROJECT_SOURCE_DIR}/networks/mainnet.cpp
${PROJECT_SOURCE_DIR}/networks/testnet.cpp
)
# ------------------------------------------------------------------------------
# Transactions Test Sources
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Builders
set(TRANSACTIONS_BUILDERS_TEST_SOURCE
${PROJECT_SOURCE_DIR}/transactions/builders/transfer.cpp
${PROJECT_SOURCE_DIR}/transactions/builders/second_signature.cpp
${PROJECT_SOURCE_DIR}/transactions/builders/delegate_registration.cpp
${PROJECT_SOURCE_DIR}/transactions/builders/vote.cpp
${PROJECT_SOURCE_DIR}/transactions/builders/ipfs.cpp
${PROJECT_SOURCE_DIR}/transactions/builders/multi_payment.cpp
${PROJECT_SOURCE_DIR}/transactions/builders/htlc_lock.cpp
${PROJECT_SOURCE_DIR}/transactions/builders/htlc_claim.cpp
${PROJECT_SOURCE_DIR}/transactions/builders/htlc_refund.cpp
${PROJECT_SOURCE_DIR}/transactions/builders/scooter_registration.cpp
)
# ------------------------------------------------------------------------------
# Defaults
set(TRANSACTIONS_DEFAULTS_TEST_SOURCE
${PROJECT_SOURCE_DIR}/transactions/defaults/fees_types.cpp
)
# ------------------------------------------------------------------------------
# Serialization/Deserialization
set(TRANSACTIONS_SERDE_TEST_SOURCE
${PROJECT_SOURCE_DIR}/transactions/deserializer.cpp
${PROJECT_SOURCE_DIR}/transactions/serializer.cpp
)
# ------------------------------------------------------------------------------
# v1 Types
set(TRANSACTIONS_TYPES_V1_TEST_SOURCE
${PROJECT_SOURCE_DIR}/transactions/types/transfer_v1.cpp
${PROJECT_SOURCE_DIR}/transactions/types/second_signature_v1.cpp
${PROJECT_SOURCE_DIR}/transactions/types/delegate_registration_v1.cpp
${PROJECT_SOURCE_DIR}/transactions/types/vote_v1.cpp
)
# ------------------------------------------------------------------------------
# Types
set(TRANSACTIONS_TYPES_TEST_SOURCE
${TRANSACTIONS_TYPES_V1_SOURCE}
${PROJECT_SOURCE_DIR}/transactions/types/transfer.cpp
${PROJECT_SOURCE_DIR}/transactions/types/second_signature.cpp
${PROJECT_SOURCE_DIR}/transactions/types/delegate_registration.cpp
${PROJECT_SOURCE_DIR}/transactions/types/vote.cpp
# ${PROJECT_SOURCE_DIR}/transactions/types/multi_signature.cpp
${PROJECT_SOURCE_DIR}/transactions/types/ipfs.cpp
${PROJECT_SOURCE_DIR}/transactions/types/multi_payment.cpp
${PROJECT_SOURCE_DIR}/transactions/types/delegate_resignation.cpp
${PROJECT_SOURCE_DIR}/transactions/types/htlc_lock.cpp
${PROJECT_SOURCE_DIR}/transactions/types/htlc_claim.cpp
${PROJECT_SOURCE_DIR}/transactions/types/htlc_refund.cpp
)
# ------------------------------------------------------------------------------
# Transactions Test Source Files
set(TRANSACTIONS_TEST_SOURCE
${TRANSACTIONS_BUILDERS_TEST_SOURCE}
${TRANSACTIONS_DEFAULTS_TEST_SOURCE}
${TRANSACTIONS_SERDE_TEST_SOURCE}
${TRANSACTIONS_TYPES_V1_TEST_SOURCE}
${TRANSACTIONS_TYPES_TEST_SOURCE}
${TRANSACTIONS_TRANSACTION_TEST_SOURCE}
${PROJECT_SOURCE_DIR}/transactions/transaction.cpp
${PROJECT_SOURCE_DIR}/transactions/transaction_v1.cpp
)
# ------------------------------------------------------------------------------
# Utils
set(UTILS_TEST_SOURCE
${PROJECT_SOURCE_DIR}/utils/base58.cpp
${PROJECT_SOURCE_DIR}/utils/crypto_helpers.cpp
${PROJECT_SOURCE_DIR}/utils/hex.cpp
${PROJECT_SOURCE_DIR}/utils/str.cpp
${PROJECT_SOURCE_DIR}/utils/unpack.cpp
)
# ------------------------------------------------------------------------------
# ARK C++ Library Test Source
set(ARK_TEST_SOURCE
${COMMON_TEST_SOURCE}
${CRYPTO_TEST_SOURCE}
${IDENTITIES_TEST_SOURCE}
${MANAGERS_TEST_SOURCE}
${NETWORKS_TEST_SOURCE}
${TRANSACTIONS_TEST_SOURCE}
${UTILS_TEST_SOURCE}
)
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Link ARK C++ Crypto to the Test Libraries
# ------------------------------------------------------------------------------
find_library(${PROJECT_NAME} PUBLIC)
add_executable(${PROJECT_NAME} ${ARK_TEST_SOURCE})
target_link_libraries(${PROJECT_NAME} ark_cpp_crypto gtest gtest_main)
add_test(NAME test COMMAND ${PROJECT_NAME})
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Coverage
# ------------------------------------------------------------------------------
if (CMAKE_BUILD_TYPE STREQUAL "Coverage")
include("${CMAKE_SOURCE_DIR}/cmake/CodeCoverage.cmake")
setup_target_for_coverage(${PROJECT_NAME}_coverage ${PROJECT_NAME}_tests coverage)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
endif() #CMAKE_BUILD_TYPE STREQUAL "Coverage"
# ------------------------------------------------------------------------------
/**
* This file is part of Ark Cpp Crypto.
*
* (c) Ark Ecosystem <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
**/
#include "gtest/gtest.h"
#include "transactions/builders/scooter_registration.hpp"
#include "common/configuration.hpp"
#include "identities/keys.hpp"
#include "test_helpers.h"
using namespace Ark::Crypto;
using namespace Ark::Crypto::transactions;
////////////////////////////////////////////////////////////////////////////////
TEST(transactions_builder, scooter_registration) { // NOLINT
const Network Radians = {
"f39a61f04d6136a690a0b675ef6eedbd053665bd343b4e4f03311f12065fb875",
1, 0xCE, 0x41,
"2019-10-25T09:05:40.856Z"
};
const Configuration radiansCfg(Radians);
const uint8_t radiansRecipient[] = {
65, 29, 252, 105, 181, 76, 127, 233, 1, 233, 29,
90, 154, 183, 131, 136, 100, 94, 36, 39, 234 };
const auto passphrase = "vehicle smile daughter torch often ask rare crucial best cargo half lady";
const auto publicKey = identities::Keys::fromPassphrase(passphrase).publicKey;
auto transaction = builder::ScooterRegistration()
.typeGroup(SCOOTER_TYPEGROUP)
.type(SCOOTER_TYPE)
.nonce(3)
.senderPublicKey(publicKey.data())
.fee(3000000000ULL)
.scooterId("1234567890")
.build(radiansCfg);
transaction.sign(passphrase);
ASSERT_TRUE(transaction.verify());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment