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
{
string from = "";
string to = "";
string counterparty = "";
bool receiving = false;
uint32 amount = 0;
timestamp time;
}

View file

@ -45,6 +45,9 @@ public:
static BankResponse GetBal(const std::string &name) noexcept;
#if MAX_LOG_SIZE > 0
static BankResponse GetLogs(const std::string &name) noexcept;
#if API_VERSION >= 2
static BankResponse GetLogsV2(const std::string &name) noexcept;
#endif
#endif
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;

View file

@ -11,9 +11,11 @@ using namespace drogon;
class api : public HttpController<api>
{
public:
#if API_VERSION >= 1
static void GetBal(req_args, const std::string &name);
static void GetLogs(req_args);
#if API_VERSION >= 2
static void GetLogsV2(req_args);
#endif
static void SendFunds(req_args);
static void VerifyPassword(req_args);
@ -33,7 +35,6 @@ public:
static void AdminAddUser(req_args);
static void DelSelf(req_args);
static void AdminDelUser(req_args);
#endif
METHOD_LIST_BEGIN
@ -41,8 +42,14 @@ public:
METHOD_ADD(api::GetBal, "/v1/user/balance?name={name}", Get, Options, "JsonFilter<false>");
#if MAX_LOG_SIZE > 0
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
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
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>");

View file

@ -12,10 +12,16 @@ struct Log
private:
ChangeFlag<true> log_flag;
std::string log_snapshot = "null";
#if API_VERSION >= 2
std::string log_snapshot_v2 = "null";
#endif
public:
std::deque<Transaction> data;
std::string GetLogs() noexcept;
void AddTrans(const std::string &from, const std::string &to, uint32_t amount, time_t time) noexcept;
std::string GetLogs(const std::string& name) 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
{
std::string from = "", to = "";
std::string counterparty = "";
bool receiving = false;
uint32_t amount = 0;
time_t time = 0;
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 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\""};
}
@ -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)
#endif
{
//if A can afford it
//if "A" can afford it
if (a.balance < amount)
{
res = {k400BadRequest, "\"Insufficient funds\""};
@ -132,7 +144,7 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
{
a.balance -= amount;
#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
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
Bank::users.modify_if(b_name, [current_time, &a_name, &b_name, amount](User &b) {
b.balance += amount;
b.log.AddTrans(a_name, b_name, amount, current_time);
b.log.AddTrans(a_name, true, amount, current_time);
});
#else
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", "*")
static thread_local ondemand::parser parser;
thread_local ondemand::parser parser;
#define SIMD_JSON_GEN \
simdjson::padded_string input(req->getBody()); \
ondemand::document doc;
@ -24,8 +24,6 @@ static thread_local ondemand::parser parser;
#define NAME_PARAM req->getParameter("name")
#if API_VERSION >= 1
//Usage
void api::GetBal(req_args, const std::string &name)
{
@ -42,6 +40,17 @@ void api::GetLogs(req_args)
callback(resp);
#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)
{
SIMD_JSON_GEN;
@ -344,4 +353,3 @@ void api::AdminDelUser(req_args)
}
RESPONSE_PARSE(std::move(res));
}
#endif

View file

@ -1,22 +1,22 @@
#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();
if (data.size() == MAX_LOG_SIZE)
{
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
{
log_snapshot.resize(0);
//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)
{
log_snapshot.reserve(predicted_size);
@ -24,18 +24,49 @@ std::string Log::GetLogs() noexcept
log_snapshot = '['; //1
for (size_t i = 0; i < data.size(); ++i)
{
log_snapshot += "{\"to\":\""; //8
log_snapshot += data[i].to; //max_name_size?
log_snapshot += "\",\"from\":\""; //10
log_snapshot += data[i].from; //max_name_size?
log_snapshot += "\",\"amount\":"; //12
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 += "{\"to\":\""; //7
log_snapshot += data[i].receiving? name : data[i].counterparty; //max_name_size?
log_snapshot += "\",\"from\":\""; //10
log_snapshot += data[i].receiving? data[i].counterparty : name; //max_name_size?
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.back() = ']';
log_flag.SetChangesOff();
}
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"
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)
{
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
@ -43,7 +43,7 @@ bank_dom::User User::Encode() const noexcept
save_log.data.reserve(this->log.data.size());
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);
}