improved Transaction structure

This commit is contained in:
EntireTwix 2022-11-28 17:06:13 -08:00
parent ab27971d8e
commit b584f5b4d5
10 changed files with 110 additions and 33 deletions

View file

@ -2,8 +2,8 @@ package bank_dom
struct Transaction struct Transaction
{ {
string from = ""; string counterparty = "";
string to = ""; bool receiving = false;
uint32 amount = 0; uint32 amount = 0;
timestamp time; timestamp time;
} }

View file

@ -45,6 +45,9 @@ public:
static BankResponse GetBal(const std::string &name) noexcept; static BankResponse GetBal(const std::string &name) noexcept;
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
static BankResponse GetLogs(const std::string &name) noexcept; static BankResponse GetLogs(const std::string &name) noexcept;
#if API_VERSION >= 2
static BankResponse GetLogsV2(const std::string &name) noexcept;
#endif
#endif #endif
static BankResponse SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept; static BankResponse SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept;
static bool VerifyPassword(const std::string &name, const std::string_view &attempt) noexcept; static bool VerifyPassword(const std::string &name, const std::string_view &attempt) noexcept;

View file

@ -11,9 +11,11 @@ using namespace drogon;
class api : public HttpController<api> class api : public HttpController<api>
{ {
public: public:
#if API_VERSION >= 1
static void GetBal(req_args, const std::string &name); static void GetBal(req_args, const std::string &name);
static void GetLogs(req_args); static void GetLogs(req_args);
#if API_VERSION >= 2
static void GetLogsV2(req_args);
#endif
static void SendFunds(req_args); static void SendFunds(req_args);
static void VerifyPassword(req_args); static void VerifyPassword(req_args);
@ -33,7 +35,6 @@ public:
static void AdminAddUser(req_args); static void AdminAddUser(req_args);
static void DelSelf(req_args); static void DelSelf(req_args);
static void AdminDelUser(req_args); static void AdminDelUser(req_args);
#endif
METHOD_LIST_BEGIN METHOD_LIST_BEGIN
@ -41,8 +42,14 @@ public:
METHOD_ADD(api::GetBal, "/v1/user/balance?name={name}", Get, Options, "JsonFilter<false>"); METHOD_ADD(api::GetBal, "/v1/user/balance?name={name}", Get, Options, "JsonFilter<false>");
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>"); METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
#if API_VERSION >= 2
METHOD_ADD(api::GetLogsV2, "/v2/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
#endif
#else #else
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>"); METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>");
#if API_VERSION >= 2
METHOD_ADD(api::GetLogsV2, "/v2/user/log", Get, Options, "JsonFilter<false>");
#endif
#endif #endif
METHOD_ADD(api::SendFunds, "/v1/user/transfer", Post, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["name"](string) and ["amount"](uint32) METHOD_ADD(api::SendFunds, "/v1/user/transfer", Post, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["name"](string) and ["amount"](uint32)
METHOD_ADD(api::VerifyPassword, "/v1/user/verify_password", Post, Options, "UserFilter<false, false>", "JsonFilter<false>"); METHOD_ADD(api::VerifyPassword, "/v1/user/verify_password", Post, Options, "UserFilter<false, false>", "JsonFilter<false>");

View file

@ -12,10 +12,16 @@ struct Log
private: private:
ChangeFlag<true> log_flag; ChangeFlag<true> log_flag;
std::string log_snapshot = "null"; std::string log_snapshot = "null";
#if API_VERSION >= 2
std::string log_snapshot_v2 = "null";
#endif
public: public:
std::deque<Transaction> data; std::deque<Transaction> data;
std::string GetLogs() noexcept; std::string GetLogs(const std::string& name) noexcept;
void AddTrans(const std::string &from, const std::string &to, uint32_t amount, time_t time) noexcept; #if API_VERSION >= 2
std::string GetLogsV2() noexcept;
#endif
void AddTrans(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept;
}; };

View file

@ -5,10 +5,20 @@
struct Transaction struct Transaction
{ {
std::string from = "", to = ""; std::string counterparty = "";
bool receiving = false;
uint32_t amount = 0; uint32_t amount = 0;
time_t time = 0; time_t time = 0;
Transaction() noexcept; Transaction() noexcept;
Transaction(const std::string &from_str, const std::string &to_str, uint32_t amount, time_t time) noexcept; Transaction(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept;
}; };
/*
TODO: v1 vs v2 functionality
TODO: FBE
TODO: v2/api
TODO: update stats on run (203 bytes)
TODO: update Docs
*/

View file

@ -89,7 +89,19 @@ BankResponse Bank::GetBal(const std::string &name) noexcept
BankResponse Bank::GetLogs(const std::string &name) noexcept BankResponse Bank::GetLogs(const std::string &name) noexcept
{ {
BankResponse res; BankResponse res;
if (!Bank::users.modify_if(name, [&res](User &u) { res = {k200OK, u.log.GetLogs()}; })) if (!Bank::users.modify_if(name, [&name, &res](User &u) { res = {k200OK, u.log.GetLogs(name)}; }))
{
return {k404NotFound, "\"User not found\""};
}
else
{
return res;
}
}
BankResponse Bank::GetLogsV2(const std::string &name) noexcept
{
BankResponse res;
if (!Bank::users.modify_if(name, [&name, &res](User &u) { res = {k200OK, u.log.GetLogsV2()}; }))
{ {
return {k404NotFound, "\"User not found\""}; return {k404NotFound, "\"User not found\""};
} }
@ -123,7 +135,7 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
if (!Bank::users.modify_if(a_name, [&a_name, &b_name, &res, amount](User &a) if (!Bank::users.modify_if(a_name, [&a_name, &b_name, &res, amount](User &a)
#endif #endif
{ {
//if A can afford it //if "A" can afford it
if (a.balance < amount) if (a.balance < amount)
{ {
res = {k400BadRequest, "\"Insufficient funds\""}; res = {k400BadRequest, "\"Insufficient funds\""};
@ -132,7 +144,7 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
{ {
a.balance -= amount; a.balance -= amount;
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
a.log.AddTrans(a_name, b_name, amount, current_time); a.log.AddTrans(b_name, false, amount, current_time);
#endif #endif
res = {k200OK, std::to_string(a.balance)}; res = {k200OK, std::to_string(a.balance)};
} }
@ -145,7 +157,7 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
#if MAX_LOG_SIZE > 0 #if MAX_LOG_SIZE > 0
Bank::users.modify_if(b_name, [current_time, &a_name, &b_name, amount](User &b) { Bank::users.modify_if(b_name, [current_time, &a_name, &b_name, amount](User &b) {
b.balance += amount; b.balance += amount;
b.log.AddTrans(a_name, b_name, amount, current_time); b.log.AddTrans(a_name, true, amount, current_time);
}); });
#else #else
Bank::users.modify_if(b_name, [amount](User &b) { b.balance += amount; }); Bank::users.modify_if(b_name, [amount](User &b) { b.balance += amount; });

View file

@ -6,7 +6,7 @@
#define CORS resp->addHeader("Access-Control-Allow-Origin", "*") #define CORS resp->addHeader("Access-Control-Allow-Origin", "*")
static thread_local ondemand::parser parser; thread_local ondemand::parser parser;
#define SIMD_JSON_GEN \ #define SIMD_JSON_GEN \
simdjson::padded_string input(req->getBody()); \ simdjson::padded_string input(req->getBody()); \
ondemand::document doc; ondemand::document doc;
@ -24,8 +24,6 @@ static thread_local ondemand::parser parser;
#define NAME_PARAM req->getParameter("name") #define NAME_PARAM req->getParameter("name")
#if API_VERSION >= 1
//Usage //Usage
void api::GetBal(req_args, const std::string &name) void api::GetBal(req_args, const std::string &name)
{ {
@ -42,6 +40,17 @@ void api::GetLogs(req_args)
callback(resp); callback(resp);
#endif #endif
} }
void api::GetLogsV2(req_args)
{
#if MAX_LOG_SIZE > 0
RESPONSE_PARSE(Bank::GetLogsV2(NAME_PARAM));
#else
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
CORS;
CACHE_FOREVER;
callback(resp);
#endif
}
void api::SendFunds(req_args) void api::SendFunds(req_args)
{ {
SIMD_JSON_GEN; SIMD_JSON_GEN;
@ -344,4 +353,3 @@ void api::AdminDelUser(req_args)
} }
RESPONSE_PARSE(std::move(res)); RESPONSE_PARSE(std::move(res));
} }
#endif

View file

@ -1,22 +1,22 @@
#include "log.h" #include "log.h"
void Log::AddTrans(const std::string &from, const std::string &to, uint32_t amount, time_t time) noexcept void Log::AddTrans(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept
{ {
log_flag.SetChangesOn(); log_flag.SetChangesOn();
if (data.size() == MAX_LOG_SIZE) if (data.size() == MAX_LOG_SIZE)
{ {
data.pop_back(); data.pop_back();
} }
data.emplace_back(from, to, amount, time); data.emplace_back(counterparty_str, receiving, amount, time);
} }
std::string Log::GetLogs() noexcept std::string Log::GetLogs(const std::string& name) noexcept
{ {
if (log_flag.GetChangeState() && data.size()) //if there are changes if (log_flag.GetChangeState() && data.size()) //if there are changes
{ {
log_snapshot.resize(0); log_snapshot.resize(0);
//re-generate snapshot //re-generate snapshot
size_t predicted_size = ((59 + (2 * max_name_size)) * data.size()) + 1; size_t predicted_size = ((57 + (2 * max_name_size)) * data.size()) + 1;
if (log_snapshot.capacity() < predicted_size) if (log_snapshot.capacity() < predicted_size)
{ {
log_snapshot.reserve(predicted_size); log_snapshot.reserve(predicted_size);
@ -24,18 +24,49 @@ std::string Log::GetLogs() noexcept
log_snapshot = '['; //1 log_snapshot = '['; //1
for (size_t i = 0; i < data.size(); ++i) for (size_t i = 0; i < data.size(); ++i)
{ {
log_snapshot += "{\"to\":\""; //8 log_snapshot += "{\"to\":\""; //7
log_snapshot += data[i].to; //max_name_size? log_snapshot += data[i].receiving? name : data[i].counterparty; //max_name_size?
log_snapshot += "\",\"from\":\""; //10 log_snapshot += "\",\"from\":\""; //10
log_snapshot += data[i].from; //max_name_size? log_snapshot += data[i].receiving? data[i].counterparty : name; //max_name_size?
log_snapshot += "\",\"amount\":"; //12 log_snapshot += "\",\"amount\":"; //11
log_snapshot += std::to_string(data[i].amount); //10? log_snapshot += std::to_string(data[i].amount); //10?
log_snapshot += ",\"time\":"; //8 log_snapshot += ",\"time\":"; //8
log_snapshot += std::to_string(data[i].time); //10? log_snapshot += std::to_string(data[i].time); //10?
log_snapshot += "},"; //2 log_snapshot += "},"; //2
} }
log_snapshot.back() = ']'; log_snapshot.back() = ']';
log_flag.SetChangesOff(); log_flag.SetChangesOff();
} }
return log_snapshot; return log_snapshot;
} }
std::string Log::GetLogsV2() noexcept
{
if (log_flag.GetChangeState() && data.size()) //if there are changes
{
log_snapshot_v2.resize(0);
//re-generate snapshot
size_t predicted_size = ((77 + max_name_size) * data.size()) + 1;
if (log_snapshot_v2.capacity() < predicted_size)
{
log_snapshot_v2.reserve(predicted_size);
}
log_snapshot_v2 = '['; //1
for (size_t i = 0; i < data.size(); ++i)
{
log_snapshot += "{\"counterparty\":\""; //17
log_snapshot += data[i].counterparty; //max_name_size?
log_snapshot += "\",\"receiving\":\""; //15
log_snapshot += std::to_string(data[i].receiving); //4
log_snapshot += "\",\"amount\":"; //11
log_snapshot += std::to_string(data[i].amount); //10?
log_snapshot += ",\"time\":"; //8
log_snapshot += std::to_string(data[i].time); //10?
log_snapshot += "},"; //2
}
log_snapshot_v2.back() = ']';
log_flag.SetChangesOff();
}
return log_snapshot_v2;
}

View file

@ -1,4 +1,4 @@
#include "transaction.h" #include "transaction.h"
Transaction::Transaction() noexcept {}; Transaction::Transaction() noexcept {};
Transaction::Transaction(const std::string &from_str, const std::string &to_str, uint32_t amount, time_t time_val) noexcept : from(from_str), to(to_str), amount(amount), time(time_val) {} Transaction::Transaction(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept : counterparty(counterparty_str), receiving(receiving), amount(amount), time(time) {}

View file

@ -29,7 +29,7 @@ User::User(const bank_dom::User &u) noexcept : balance(u.balance), password(u.pa
for (; i < u.logs.value().data.size(); ++i) for (; i < u.logs.value().data.size(); ++i)
{ {
const bank_dom::Transaction &temp = u.logs.value().data[i]; const bank_dom::Transaction &temp = u.logs.value().data[i];
log.data.emplace_front(temp.from, temp.to, temp.amount, temp.time); log.data.emplace_front(temp.counterparty, temp.receiving, temp.amount, temp.time);
} }
} }
#endif #endif
@ -43,7 +43,7 @@ bank_dom::User User::Encode() const noexcept
save_log.data.reserve(this->log.data.size()); save_log.data.reserve(this->log.data.size());
for (const Transaction &t : this->log.data) for (const Transaction &t : this->log.data)
{ {
save_log.data.emplace_back(t.from, t.to, t.amount, t.time); save_log.data.emplace_back(t.counterparty, t.receiving, t.amount, t.time);
} }
return bank_dom::User(balance, password, save_log); return bank_dom::User(balance, password, save_log);
} }