载入中...
搜索中...
未找到
ResourceAccount.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <atomic>
5#include <cctype>
6#include <limits>
7#include <utility>
8
9namespace eve::resource {
10namespace {
11
12std::atomic<std::uint64_t>& nextAccountNonce() {
13 static std::atomic<std::uint64_t> next{1};
14 return next;
15}
16
17eve::Diagnostic invalidArgument(std::string message, std::string path = {}) {
19}
20
21eve::Diagnostic invariantFailure(std::string message, std::string path = {}) {
23}
24
25} // namespace
26
28 auto& counter = nextAccountNonce();
29 std::uint64_t value = counter.load(std::memory_order_relaxed);
30 for (;;) {
31 if (value == 0 || value == std::numeric_limits<std::uint64_t>::max())
32 return eve::Result<AccountNonce>::failure(invariantFailure("resource account nonce exhausted", "account"));
33 if (counter.compare_exchange_weak(value, value + 1, std::memory_order_relaxed, std::memory_order_relaxed))
35 }
36}
37
39 if (text.empty())
40 return eve::Result<ResourceId>::failure(invalidArgument("resource id must not be empty", "resource"));
41 if (text.size() > 128)
42 return eve::Result<ResourceId>::failure(invalidArgument("resource id is too long", "resource"));
43 for (const unsigned char character : text) {
44 if (std::iscntrl(character) || std::isspace(character))
46 invalidArgument("resource id must not contain whitespace or control characters", "resource"));
47 }
49}
50
52 if (value < 0)
53 return eve::Result<Amount>::failure(invalidArgument("resource amount must not be negative", "amount"));
55}
56
58 if (other.value_ > std::numeric_limits<std::int64_t>::max() - value_)
59 return eve::Result<Amount>::failure(invariantFailure("resource amount addition overflowed", "amount"));
60 return eve::Result<Amount>::success(Amount(value_ + other.value_));
61}
62
63eve::Result<ResourceCost> ResourceCost::create(std::string_view resourceId, std::int64_t amountValue) {
64 auto resource = ResourceId::parse(resourceId);
66 auto amount = Amount::from(amountValue);
68 if (amount.value().isZero())
69 return eve::Result<ResourceCost>::failure(invalidArgument("resource cost amount must be positive", "amount"));
71 ResourceCost{std::move(resource).takeValue(), std::move(amount).takeValue()});
72}
73
74eve::Result<CostSpec> CostSpec::create(std::vector<ResourceCost> items) {
75 if (items.empty())
76 return eve::Result<CostSpec>::failure(invalidArgument("resource cost must contain at least one item", "cost"));
77 for (const auto& item : items) {
78 if (!item.resource.isValid())
80 invalidArgument("resource cost contains an invalid resource id", "cost.resource"));
81 if (item.amount.value() <= 0)
83 invalidArgument("resource cost amounts must be positive", "cost.amount"));
84 }
85
86 std::sort(items.begin(), items.end(),
87 [](const auto& left, const auto& right) { return left.resource.value() < right.resource.value(); });
88
89 std::vector<ResourceCost> canonical;
90 canonical.reserve(items.size());
91 for (auto& item : items) {
92 if (canonical.empty() || canonical.back().resource != item.resource) {
93 canonical.push_back(std::move(item));
94 continue;
95 }
96 auto combined = canonical.back().amount.checkedAdd(item.amount);
97 if (!combined) return eve::Result<CostSpec>::failure(combined.status());
98 canonical.back().amount = std::move(combined).takeValue();
99 }
100 return eve::Result<CostSpec>::success(CostSpec(std::move(canonical)));
101}
102
103eve::Result<CostSpec> CostSpec::from(std::initializer_list<CostInput> items) {
104 if (items.size() == 0)
105 return eve::Result<CostSpec>::failure(invalidArgument("resource cost must contain at least one item", "cost"));
106
107 std::vector<ResourceCost> parsed;
108 parsed.reserve(items.size());
109 for (const auto& input : items) {
110 auto item = ResourceCost::create(input.resource, input.amount);
111 if (!item) return eve::Result<CostSpec>::failure(item.status());
112 parsed.push_back(std::move(item).takeValue());
113 }
114 return create(std::move(parsed));
115}
116
117eve::Result<CostSpec> CostSpec::single(std::string_view resource, std::int64_t amount) {
118 return from({CostInput{resource, amount}});
119}
120
121} // namespace eve::resource
double value
std::string from
EvpackChunkInput input
Definition Evpack.cpp:170
std::string message
HexVec3 left
HexVec3 right
std::string text
std::string path
Definition PlayHost.cpp:110
Strongly typed, transaction-friendly resource cost protocol.
std::string resource
A structured explanation of a failed, degraded, or noteworthy result.
Definition Diagnostic.h:94
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Opaque process-local identity of the account that issued a credential.
Non-negative integral quantity used by resource accounts.
constexpr std::int64_t value() const noexcept
Return the native quantity at an explicit adapter boundary.
eve::Result< Amount > checkedAdd(Amount other) const
Add two quantities with overflow checking.
static eve::Result< Amount > from(std::int64_t value)
Validate and construct an amount.
constexpr Amount() noexcept=default
Construct zero.
static eve::Result< CostSpec > from(std::initializer_list< CostInput > items)
Build a cost from string/integer pairs.
CostSpec()=default
Construct an invalid empty cost; use create/from/single for input.
const std::vector< ResourceCost > & items() const noexcept
Return canonical items as a read-only borrowed view.
static eve::Result< CostSpec > create(std::vector< ResourceCost > items)
Validate and canonicalize resource items.
static eve::Result< CostSpec > single(std::string_view resource, std::int64_t amount)
Build a one-resource cost.
ResourceId()=default
Construct an invalid resource id.
static eve::Result< ResourceId > parse(std::string_view text)
Parse a resource id at a public input boundary.
eve::Result< AccountNonce > allocateAccountNonce()
Allocate a process-local account identity for a credential issuer.
Convenient unvalidated input used by CostSpec::from().
One positive resource and quantity pair in a canonical cost.
static eve::Result< ResourceCost > create(std::string_view resourceId, std::int64_t amountValue)
Construct and validate one cost item.