Add safe bank failure diagnostics for T5 and T6
Address #14 with request correlation, bounded parser reasons, startup version reporting, and rate-limited storage and settlement logs. Preserve accounting and API identity contracts, extend portable tests, and update release versions and rollout guidance.
This commit is contained in:
@@ -29,30 +29,42 @@ namespace utils::bank
|
||||
|
||||
acknowledgement parse_acknowledgement(const std::string& response)
|
||||
{
|
||||
acknowledgement result;
|
||||
if (response.empty() || response.size() >= max_body_size) return result;
|
||||
auto invalid = [](const char* reason)
|
||||
{
|
||||
acknowledgement value;
|
||||
value.reason = reason;
|
||||
return value;
|
||||
};
|
||||
if (response.empty()) return invalid("empty_body");
|
||||
if (response.size() >= max_body_size) return invalid("body_limit");
|
||||
const auto data = nlohmann::json::parse(response, nullptr, false);
|
||||
if (!data.is_object()) return result;
|
||||
if (data.is_discarded()) return invalid("invalid_json");
|
||||
if (!data.is_object()) return invalid("schema");
|
||||
try
|
||||
{
|
||||
if (!data.at("ok").is_boolean()) return result;
|
||||
acknowledgement result;
|
||||
if (!data.at("ok").is_boolean()) return invalid("schema");
|
||||
result.state = data.at("state").get<std::string>();
|
||||
result.code = data.at("code").get<std::string>();
|
||||
result.id = data.at("request_id").get<std::string>();
|
||||
if (result.id.size() > 64 || result.code.size() > 64 ||
|
||||
(result.state != "balance" && result.state != "prepared" && result.state != "committed" &&
|
||||
result.state != "cancelled" && result.state != "rejected")) return {};
|
||||
if (result.id.size() > 64 || result.code.size() > 64)
|
||||
return invalid("field_limit");
|
||||
if (result.state != "balance" && result.state != "prepared" && result.state != "committed" &&
|
||||
result.state != "cancelled" && result.state != "rejected") return invalid("state");
|
||||
for (const auto* key : {"amount", "balance"})
|
||||
if (!data.at(key).is_number_integer() || data.at(key) < 0 || data.at(key) > 1000000) return {};
|
||||
if (!data.at(key).is_number_integer() || data.at(key) < 0 || data.at(key) > 1000000)
|
||||
return invalid("amount_range");
|
||||
result.amount = data.at("amount").get<int>();
|
||||
result.balance = data.at("balance").get<int>();
|
||||
if (data.at("ok").get<bool>() != (result.state != "rejected") ||
|
||||
(result.state != "balance" && result.id.empty()) ||
|
||||
((result.state == "prepared" || result.state == "committed") && result.amount == 0)) return {};
|
||||
if (data.at("ok").get<bool>() != (result.state != "rejected")) return invalid("ok_state");
|
||||
if (result.state != "balance" && result.id.empty()) return invalid("missing_id");
|
||||
if ((result.state == "prepared" || result.state == "committed") && result.amount == 0)
|
||||
return invalid("zero_transfer");
|
||||
result.valid = true;
|
||||
result.reason = "ok";
|
||||
return result;
|
||||
}
|
||||
catch (...) { return {}; }
|
||||
return result;
|
||||
catch (...) { return invalid("schema"); }
|
||||
}
|
||||
|
||||
outbox::outbox(std::filesystem::path root, std::string server, std::string endpoint)
|
||||
|
||||
Reference in New Issue
Block a user