Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: transaction to JSON #54

Merged
merged 19 commits into from Feb 4, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Expand Up @@ -10,3 +10,6 @@
[submodule "examples/cmake_example/lib/cpp-crypto"]
path = examples/cmake_example/lib/cpp-crypto
url = https://github.com/ArkEcosystem/cpp-crypto.git
[submodule "src/lib/ArduinoJson"]
path = src/lib/ArduinoJson
url = https://github.com/bblanchon/ArduinoJson
1 change: 1 addition & 0 deletions docs/INSTALL_ARDUINO.MD
Expand Up @@ -17,6 +17,7 @@ Using the Arduino IDE's built in Library Manager,
install the following Libraries
- micro-ecc
- AUnit
- ArduinoJson

#

Expand Down
4 changes: 2 additions & 2 deletions docs/INSTALL_PLATFORMIO.md
Expand Up @@ -18,8 +18,8 @@ or


also install platformio dependencies:
> install AUnit (2778), micro-ecc (1665) bip39 (5886) libraries
>```platformio lib -g install 2778 1665 5886```
> install AUnit (2778), micro-ecc (1665) bip39 (5886) ArduinoJson@5.13.4 libraries
>```platformio lib -g install 2778 1665 5886 ArduinoJson@5.13.4```

#

Expand Down
2 changes: 1 addition & 1 deletion platformio.ini
Expand Up @@ -13,7 +13,7 @@ description = "A simple Cryptography Implementation in C++ for the ARK Blockchai

[common]
lib_ldf_mode = off
lib_deps = micro-ecc, bip39@^1.1
lib_deps = micro-ecc, bip39@^1.1, ArduinoJson@5.13.4
build_flags = -I./src/ -I./src/bcl -I./src/include/cpp-crypto
src_filter = +<*> -<.git/> -<examples/> -<lib> -<CMakeFiles>
upload_speed = 921600
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Expand Up @@ -54,6 +54,7 @@ set(cpp_crypto_build_include_dirs
)
include_directories(${cpp_crypto_build_include_dirs})
include_directories(${PROJECT_SOURCE_DIR}/lib/uECC)
include_directories(${PROJECT_SOURCE_DIR}/lib/ArduinoJson)

target_include_directories( ${PROJECT_NAME}
PUBLIC ${cpp_crypto_build_include_dirs}
Expand Down
13 changes: 13 additions & 0 deletions src/helpers/json.h
@@ -0,0 +1,13 @@

#ifndef JSON_H
#define JSON_H

/* ArduinoJson Presets */
#define ARDUINOJSON_USE_LONG_LONG 1
#define ARDUINOJSON_ENABLE_STD_STRING 1 // Enable 'std::string'
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 // disable 'String'

/* ArduinoJson Header */
#include "ArduinoJson.h"

#endif
15 changes: 12 additions & 3 deletions src/include/cpp-crypto/transactions/transaction.h
Expand Up @@ -10,12 +10,15 @@
#ifndef TRANSACTION_H
#define TRANSACTION_H

#include <string>
#include "helpers/encoding/hex.h"
#include "helpers/crypto_helpers.h"
#include "identities/privatekey.h"
#include "identities/publickey.h"

#include <map>
#include <string>
#include <vector>

namespace Ark {
namespace Crypto {
namespace Transactions {
Expand All @@ -39,14 +42,20 @@ struct TransactionAsset {
};

class Transaction {
public:
public:
Transaction();

std::string getId() const;

std::string sign(const char* passphrase);
std::string secondSign(const char* passphrase);

bool verify() const;
bool secondVerify(const char* secondPublicKey) const;

std::vector<uint8_t> toBytes(bool skipSignature = true, bool skipSecondSignature = true) const;
std::map<std::string, std::string> toArray();
std::string toJson();

uint8_t header = 0;
uint8_t network = 0;
Expand All @@ -69,7 +78,7 @@ class Transaction {
uint64_t fee = 0;
uint64_t timelock = 0;

private:
private:
bool internalVerify(std::string publicKey, std::vector<uint8_t> bytes, std::string signature) const;
};

Expand Down
1 change: 1 addition & 0 deletions src/lib/ArduinoJson
Submodule ArduinoJson added at 0685a3
231 changes: 221 additions & 10 deletions src/transactions/transaction.cpp
Expand Up @@ -3,9 +3,12 @@
#include "enums/types.h"
#include "helpers/crypto.h"
#include "helpers/crypto_helpers.h"
#include "helpers/json.h"
#include "identities/address.h"
#include "identities/privatekey.h"

#include <map>

using namespace Ark::Crypto::Identities;

Ark::Crypto::Transactions::Transaction::Transaction() {}
Expand Down Expand Up @@ -51,8 +54,19 @@ bool Ark::Crypto::Transactions::Transaction::secondVerify(const char* secondPubl
return this->internalVerify(secondPublicKey, this->toBytes(false), this->secondSignature);
}

std::vector<uint8_t> Ark::Crypto::Transactions::Transaction::toBytes(bool skipSignature,
bool skipSecondSignature) const {
bool Ark::Crypto::Transactions::Transaction::internalVerify(
std::string publicKey,
std::vector<uint8_t> bytes,
std::string signature) const {
const auto hash = Sha256::getHash(&bytes[0], bytes.size());
const auto key = Identities::PublicKey::fromHex(publicKey.c_str());
auto signatureBytes = HexToBytes(signature.c_str());
return cryptoVerify(key, hash, signatureBytes);
}

std::vector<uint8_t> Ark::Crypto::Transactions::Transaction::toBytes(
bool skipSignature,
bool skipSecondSignature) const {
std::vector<uint8_t> bytes;

pack(bytes, this->type);
Expand All @@ -61,8 +75,10 @@ std::vector<uint8_t> Ark::Crypto::Transactions::Transaction::toBytes(bool skipSi
const auto senderKeyBytes = HexToBytes(this->senderPublicKey.c_str());
bytes.insert(std::end(bytes), std::begin(senderKeyBytes), std::end(senderKeyBytes));

const auto skipRecipientId =
type == Enums::Types::SECOND_SIGNATURE_REGISTRATION || type == Enums::Types::MULTI_SIGNATURE_REGISTRATION;
const auto skipRecipientId = type
== Enums::Types::SECOND_SIGNATURE_REGISTRATION
|| type == Enums::Types::MULTI_SIGNATURE_REGISTRATION;

if (!this->recipientId.empty() && !skipRecipientId) {
std::vector<std::uint8_t> recipientIdBytes = Address::bytesFromBase58Check(this->recipientId.c_str());
bytes.insert(std::end(bytes), std::begin(recipientIdBytes), std::end(recipientIdBytes));
Expand Down Expand Up @@ -119,10 +135,205 @@ std::vector<uint8_t> Ark::Crypto::Transactions::Transaction::toBytes(bool skipSi
return bytes;
}

bool Ark::Crypto::Transactions::Transaction::internalVerify(std::string publicKey, std::vector<uint8_t> bytes,
std::string signature) const {
const auto hash = Sha256::getHash(&bytes[0], bytes.size());
const auto key = Identities::PublicKey::fromHex(publicKey.c_str());
auto signatureBytes = HexToBytes(signature.c_str());
return cryptoVerify(key, hash, signatureBytes);
std::map<std::string, std::string> Ark::Crypto::Transactions::Transaction::toArray() {
// buffers for variable and non-string type-values.
char amount[24], assetName[16], assetValue[512], fee[24], network[8], signatures[512], timestamp[36], type[8], version[8];

// Amount
sprintf(amount, "%llu", this->amount);

// Asset
if (this->type == 0) { // Transfer
//do nothing
} else if (this->type == 1) { // Second Signature Registration

strcpy(assetName, "publicKey");
strcpy(assetValue, this->asset.signature.publicKey.c_str());

} else if (this->type == 2) { // Delegate Registration

strcpy(assetName, "username");
strcpy(assetValue, this->asset.delegate.username.c_str());

} else if (this->type == 3) { // Vote

strcpy(assetName, "votes");
strcpy(assetValue, "");
for (unsigned int i = 0; i < this->asset.votes.size(); ++i) {
strcat(assetValue, this->asset.votes[i].c_str());

if (i < this->asset.votes.size() - 1) {
strcat(assetValue, ",");
}
}

// } else if (this->type == 4) { // Multisignature Registration
// // TODO
// } else if (this->type == 5) { // IPFS
// // TBD
// } else if (this->type == 6) { // Timelock Registration
// // TBD
// } else if (this->type == 7) { // Multi-Payment
// // TBD
// } else if (this->type == 8) { // Delegate Resignation
// // TBD
};

// Fee
// fee << this->fee;
sprintf(fee, "%llu", this->fee);

// Signatures
strcpy(signatures, "");
for (unsigned int i = 0; i < this->signatures.size(); ++i) {
strcat(signatures, this->signatures[i].c_str());
if (i < this->signatures.size() - 1) {
strcpy(signatures, ",");
}
}

// Network
sprintf(network, "%d", this->network);

// Timestamp
sprintf(timestamp, "%d", this->timestamp);

// Type
sprintf(type, "%d", this->type);

// Version
sprintf(version, "%d", this->version);

return {
{"amount", amount},
{assetName, assetValue},
{"fee", fee},
{"id", this->id},
{"network", network},
{"recipientId", this->recipientId},
{"secondSignature", this->secondSignature},
{"senderPublicKey", this->senderPublicKey},
{"signature", this->signature},
{"signatures", signatures},
{"signSignature", this->signSignature},
{"timestamp", timestamp},
{"type", type},
{"vendorField", this->vendorField},
{"version", version}
};
}

std::string Ark::Crypto::Transactions::Transaction::toJson() {
std::map<std::string, std::string> txArray = this->toArray();

const size_t capacity = JSON_OBJECT_SIZE(15);
DynamicJsonBuffer jsonBuffer(capacity);

JsonObject& root = jsonBuffer.createObject();

// Amount
root["amount"] = txArray["amount"];

// Asset
if (this->type == 0) { // Transfer
//do nothing
} else if (this->type == 1) { // Second Signature Registration

JsonObject& tAsset = root.createNestedObject("asset");
JsonObject& signature = tAsset.createNestedObject("signature");
signature["publicKey"] = txArray["publicKey"];

} else if (this->type == 2) { // Delegate Registration

JsonObject& dAsset = root.createNestedObject("asset");
JsonObject& delegate = dAsset.createNestedObject("delegate");
delegate["username"] = txArray["username"];

}else if (this->type == 3) { // Vote

JsonObject& vAsset = root.createNestedObject("asset");
JsonArray& votes = vAsset.createNestedArray("votes");

std::string::size_type lastPos = txArray["votes"].find_first_not_of(",", 0);
std::string::size_type pos = txArray["votes"].find_first_of(",", lastPos);
while (std::string::npos != pos || std::string::npos != lastPos) {
votes.add(txArray["votes"].substr(lastPos, pos - lastPos));
lastPos = txArray["votes"].find_first_not_of(",", pos);
pos = txArray["votes"].find_first_of(",", lastPos);
}

// } else if (this->type == 4) { // Multisignature Registration
// // TODO
// } else if (this->type == 5) { // IPFS
// // TBD
// } else if (this->type == 6) { // Timelock Registration
// // TBD
// } else if (this->type == 7) { // Multi-Payment
// // TBD
// } else if (this->type == 8) { // Delegate Resignation
// // TBD
};

// Fee
root["fee"] = txArray["fee"];

// Id
root["id"] = txArray["id"];

// Network
if (txArray["network"] != "0") {
root["network"] = txArray["network"];
}

// RecipientId
root["recipientId"] = txArray["recipientId"];

// SecondSignature
if (std::strlen(txArray["secondSignature"].c_str()) > 0) {
root["secondSignature"] = txArray["secondSignature"];
}

// SenderPublicKey
root["senderPublicKey"] = txArray["senderPublicKey"];

// Signature
root["signature"] = txArray["signature"];

// Signatures
if (this->signatures.size() > 0) {
JsonArray& signatures = root.createNestedArray("signatures");
std::string::size_type lastPos = txArray["signatures"].find_first_not_of(",", 0);
std::string::size_type pos = txArray["signatures"].find_first_of(",", lastPos);
while (std::string::npos != pos || std::string::npos != lastPos) {
signatures.add(txArray["signatures"].substr(lastPos, pos - lastPos));
lastPos = txArray["signatures"].find_first_not_of(",", pos);
pos = txArray["signatures"].find_first_of(",", lastPos);
}
}

// SignSignature
if (std::strlen(txArray["signSignature"].c_str()) > 0) {
root["signSignature"] = txArray["signSignature"];
}

// Timestamp
root["timestamp"] = txArray["timestamp"];

// Type
root["type"] = txArray["type"];

// VendorField
if (std::strlen(txArray["vendorField"].c_str()) > 0) {
root["vendorField"] = txArray["vendorField"];
}

// Version
if (txArray["version"] != "0") {
root["version"] = txArray["version"];
}

char jsonChar[root.measureLength() + 1];
root.printTo((char*)jsonChar, sizeof(jsonChar));

return jsonChar;
}