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

Producers support staged tx #961

Merged
merged 18 commits into from
Jan 10, 2025
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
BasedOnStyle: Chromium
BreakBeforeBraces: Allman
ColumnLimit: '100'
IndentWidth: '3'
ColumnLimit: "100"
IndentWidth: "3"
NamespaceIndentation: All
ReflowComments: false
AlignConsecutiveDeclarations: true
Expand Down
1 change: 1 addition & 0 deletions libraries/psibase/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ function(add suffix)
../../services/system/CpuLimit/include
../../services/system/HttpServer/include
../../services/system/SetCode/include
../../services/system/StagedTx/service/cpp/include
../../services/system/Transact/include
../../services/user/CommonApi/include
../../services/user/Explorer/include
Expand Down
5 changes: 3 additions & 2 deletions libraries/psibase/common/include/psibase/block.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ namespace psibase
{
AccountNumber name;
Claim auth;
friend bool operator==(const Producer&, const Producer&) = default;

friend bool operator==(const Producer&, const Producer&) = default;
PSIO_REFLECT(Producer, name, auth);
};

Expand Down Expand Up @@ -214,7 +215,7 @@ namespace psibase
BlockNum blockNum = 0; // TODO: pack into previous instead?
BlockTime time;
AccountNumber producer;
TermNum term;
TermNum term = 0;
BlockNum commitNum;

// Holds a sha256 of the current JointConsensus
Expand Down
15 changes: 9 additions & 6 deletions libraries/psibase/tester/include/psibase/tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@

namespace psibase
{
using KeyList = std::vector<std::pair<SystemService::AuthSig::SubjectPublicKeyInfo,
SystemService::AuthSig::PrivateKeyInfo>>;
using KeyPair = std::pair<SystemService::AuthSig::SubjectPublicKeyInfo,
SystemService::AuthSig::PrivateKeyInfo>;
using KeyList = std::vector<KeyPair>;

inline std::string show(bool include, TransactionTrace t)
{
Expand Down Expand Up @@ -56,6 +57,8 @@ namespace psibase
if (auto at = std::get_if<ActionTrace>(&inner.inner))
if (isUserAction(at->action))
top_traces.push_back(at);
if (top_traces.size() & 1)
std::cout << prettyTrace(trimRawData(t)).c_str();
check(!(top_traces.size() & 1), "unexpected number of action traces");
check(2 * num + 1 < top_traces.size(), "trace not found");
return *top_traces[2 * num + 1];
Expand Down Expand Up @@ -313,13 +316,13 @@ namespace psibase
{
if (response.contentType == "text/html")
{
abortMessage(std::to_string(static_cast<std::uint16_t>(response.status)) + " " +
std::string(response.body.begin(), response.body.end()));
abortMessage(std::to_string(static_cast<std::uint16_t>(response.status)) + " "
+ std::string(response.body.begin(), response.body.end()));
}
else
{
abortMessage("Request returned " +
std::to_string(static_cast<std::uint16_t>(response.status)));
abortMessage("Request returned "
+ std::to_string(static_cast<std::uint16_t>(response.status)));
}
}
if (response.contentType != "application/json")
Expand Down
23 changes: 14 additions & 9 deletions programs/psitest/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,8 @@ struct test_chain
},
status->consensus.next->consensus.data);
}
if (!status->consensus.next ||
status->current.commitNum < status->consensus.next->blockNum)
if (!status->consensus.next
|| status->current.commitNum < status->consensus.next->blockNum)
{
std::visit(
[&](const auto& c)
Expand All @@ -380,7 +380,12 @@ struct test_chain
}
}

blockContext->start(time, producer);
// These are not the correct values if we want the chain to actually
// sync correctly, but it's sufficient for the tester to test services.
auto term = status->current.term;
auto commitNum = status->current.blockNum;

blockContext->start(time, producer, term, commitNum);
blockContext->callStartBlock();
}

Expand Down Expand Up @@ -628,8 +633,8 @@ struct HttpSocket : psibase::AutoCloseSocket
case psibase::HttpStatus::notFound:
break;
default:
psibase::check(false, "HTTP response code not allowed: " +
std::to_string(static_cast<std::uint16_t>(status)));
psibase::check(false, "HTTP response code not allowed: "
+ std::to_string(static_cast<std::uint16_t>(status)));
}
sendImpl(std::vector(data.begin(), data.end()));
}
Expand Down Expand Up @@ -828,8 +833,8 @@ struct callbacks

file* get_file(int32_t file_index)
{
if (file_index < 0 || static_cast<uint32_t>(file_index) >= state.files.size() ||
!state.files[file_index].f)
if (file_index < 0 || static_cast<uint32_t>(file_index) >= state.files.size()
|| !state.files[file_index].f)
return nullptr;
return &state.files[file_index];
}
Expand Down Expand Up @@ -1397,8 +1402,8 @@ struct callbacks
socket->queryTimes.databaseTime =
std::chrono::duration_cast<std::chrono::microseconds>(tc.databaseTime);
socket->queryTimes.wasmExecTime =
std::chrono::duration_cast<std::chrono::microseconds>(tc.getBillableTime() -
tc.databaseTime);
std::chrono::duration_cast<std::chrono::microseconds>(tc.getBillableTime()
- tc.databaseTime);
socket->queryTimes.startTime = startTime;
});
psibase::Action action{
Expand Down
16 changes: 14 additions & 2 deletions rust/psibase/src/services/transact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,18 @@ pub mod auth_interface {
///
/// * `sender`: The sender account for the transaction potentially being authorized.
/// * `authorizers`: The set of accounts that have already authorized the execution of the transaction.
/// * `authSet`: The set of accounts that are already being checked for authorization.
/// If the sender is already in this set, then the function should return false.
///
/// Returns:
/// * `true`: The authorizers are sufficient to authorize a transaction from the sender.
/// * `false`: The authorizers are not sufficient to authorize a transaction from the sender.
#[action]
fn isAuthSys(sender: crate::AccountNumber, authorizers: Vec<crate::AccountNumber>) -> bool {
fn isAuthSys(
sender: crate::AccountNumber,
authorizers: Vec<crate::AccountNumber>,
authSet: Option<Vec<crate::AccountNumber>>,
) -> bool {
unimplemented!()
}

Expand All @@ -172,12 +178,18 @@ pub mod auth_interface {
///
/// * `sender`: The sender account for the transaction potentially being rejected.
/// * `rejecters`: The set of accounts that have already authorized the rejection of the transaction.
/// * `authSet`: The set of accounts that are already being checked for authorization.
/// If the sender is already in this set, then the function should return false.
///
/// Returns:
/// * `true`: The rejecters are sufficient to reject a transaction from the sender.
/// * `false`: The rejecters are not sufficient to reject a transaction from the sender.
#[action]
fn isRejectSys(sender: crate::AccountNumber, rejecters: Vec<crate::AccountNumber>) -> bool {
fn isRejectSys(
sender: crate::AccountNumber,
rejecters: Vec<crate::AccountNumber>,
authSet: Option<Vec<crate::AccountNumber>>,
) -> bool {
unimplemented!()
}
}
Expand Down
9 changes: 8 additions & 1 deletion services/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,22 @@ add_subdirectory(psibase_tests)
if(DEFINED IS_WASM)
install(DIRECTORY system/Accounts/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY system/AuthAny/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY system/AuthDelegate/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY system/AuthSig/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY system/Producers/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY system/HttpServer/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY system/Producers/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY system/SetCode/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY system/StagedTx/service/cpp/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY system/Transact/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY system/VerifySig/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")

install(DIRECTORY user/Brotli/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY user/CommonApi/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY user/Events/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY user/Explorer/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY user/Fractal/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY user/Identity/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY user/Invite/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY user/Nft/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY user/Sites/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY user/Symbol/include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")
Expand Down
6 changes: 6 additions & 0 deletions services/system/Accounts/include/services/system/Accounts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ namespace SystemService
/// Returns data about an account from the accounts table
std::optional<Account> getAccount(psibase::AccountNumber name);

/// Returns the auth service of the specified account
///
/// Aborts if the account does not exist
psibase::AccountNumber getAuthOf(psibase::AccountNumber account);

/// Return value indicates whether the account `name` exists
bool exists(psibase::AccountNumber name);

Expand All @@ -117,6 +122,7 @@ namespace SystemService
method(newAccount, name, authService, requireNew),
method(setAuthServ, authService),
method(getAccount, name),
method(getAuthOf, account),
method(exists, name),
method(billCpu, name, amount)
//
Expand Down
11 changes: 9 additions & 2 deletions services/system/Accounts/src/Accounts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ namespace SystemService
auto accountTable = tables.open<AccountTable>();
auto accountIndex = accountTable.getIndex<0>();
auto account = accountIndex.get((getSender()));
check(account.has_value(), "account does not exist");
check(account.has_value(), "account " + getSender().str() + " does not exist");

to<AuthInterface>(authService).canAuthUserSys(getSender());

Expand All @@ -117,6 +117,13 @@ namespace SystemService
return accountIndex.get(name);
}

psibase::AccountNumber Accounts::getAuthOf(psibase::AccountNumber account)
{
auto accountRow = getAccount(account);
check(accountRow.has_value(), "account " + account.str() + " does not exist");
return accountRow->authService;
}

bool Accounts::exists(AccountNumber name)
{
return getAccount(name) != std::nullopt;
Expand All @@ -129,7 +136,7 @@ namespace SystemService
auto accountTable = tables.open<AccountTable>();
auto accountIndex = accountTable.getIndex<0>();
auto row = accountIndex.get(name);
check(!!row, "account does not exist");
check(!!row, "account " + name.str() + " does not exist");
if (row->resourceBalance)
{
row->resourceBalance->billCpu(amount);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ namespace SystemService
/// Returns:
/// * `true`: If the sender's owner is among the authorizers, or if the sender's owner's auth
/// service would authorize the transaction
/// * `false`: If not returning true
bool isAuthSys(psibase::AccountNumber sender,
std::vector<psibase::AccountNumber> authorizers);
/// * `false`: If not returning true, or on recursive checks for the same sender
bool isAuthSys(psibase::AccountNumber sender,
std::vector<psibase::AccountNumber> authorizers,
std::optional<std::vector<psibase::AccountNumber>> authSet);

/// Check whether a specified set of rejecter accounts are sufficient to reject (cancel) a
/// transaction from a specified sender.
Expand All @@ -74,9 +75,10 @@ namespace SystemService
/// Returns:
/// * `true`: If the sender's owner is among the rejecters, or if the sender's owner's auth
/// service would reject the transaction
/// * `false`: If not returning true
bool isRejectSys(psibase::AccountNumber sender,
std::vector<psibase::AccountNumber> rejecters);
/// * `false`: If not returning true, or on recursive checks for the same sender
bool isRejectSys(psibase::AccountNumber sender,
std::vector<psibase::AccountNumber> rejecters,
std::optional<std::vector<psibase::AccountNumber>> authSet);

/// Set the owner of the sender account
///
Expand All @@ -92,8 +94,8 @@ namespace SystemService
PSIO_REFLECT(AuthDelegate, //
method(checkAuthSys, flags, requester, sender, action, allowedActions, claims),
method(canAuthUserSys, user),
method(isAuthSys, sender, authorizers),
method(isRejectSys, sender, rejecters),
method(isAuthSys, sender, authorizers, authSet),
method(isRejectSys, sender, rejecters, authSet),
method(setOwner, owner)
//
)
Expand Down
40 changes: 27 additions & 13 deletions services/system/AuthDelegate/src/AuthDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,48 @@ namespace SystemService
getOwner(user);
}

bool AuthDelegate::isAuthSys(psibase::AccountNumber sender,
std::vector<psibase::AccountNumber> authorizers)
bool AuthDelegate::isAuthSys(psibase::AccountNumber sender,
std::vector<psibase::AccountNumber> authorizers,
std::optional<std::vector<psibase::AccountNumber>> authSet_opt)
{
auto authSet = authSet_opt ? std::move(*authSet_opt) : std::vector<AccountNumber>{};

// Base case to prevent infinite recursion
if (std::ranges::contains(authSet, sender))
return false;

authSet.push_back(sender);

auto owner = getOwner(sender);

if (std::ranges::contains(authorizers, owner))
return true;

auto _ = recurse();
return authServiceOf(owner).isAuthSys(owner, std::move(authorizers));
return authServiceOf(owner).isAuthSys(owner, std::move(authorizers),
std::optional(std::move(authSet)));
}

bool AuthDelegate::isRejectSys(psibase::AccountNumber sender,
std::vector<psibase::AccountNumber> rejecters)
bool AuthDelegate::isRejectSys(psibase::AccountNumber sender,
std::vector<psibase::AccountNumber> rejecters,
std::optional<std::vector<psibase::AccountNumber>> authSet_opt)
{
auto authSet = authSet_opt ? std::move(*authSet_opt) : std::vector<AccountNumber>{};

// Base case to prevent infinite recursion
if (std::ranges::contains(authSet, sender))
return false;

authSet.push_back(sender);

auto owner = getOwner(sender);

if (std::ranges::contains(rejecters, owner))
return true;

auto _ = recurse();
return authServiceOf(owner).isRejectSys(owner, std::move(rejecters));
return authServiceOf(owner).isRejectSys(owner, std::move(rejecters),
std::make_optional(authSet));
}

void AuthDelegate::setOwner(psibase::AccountNumber owner)
Expand All @@ -70,13 +90,7 @@ namespace SystemService

Actor<AuthInterface> AuthDelegate::authServiceOf(psibase::AccountNumber account)
{
auto accountRow = to<Accounts>().getAccount(account);
if (!accountRow)
{
abortMessage("unknown account \"" + account.str() + "\"");
}

return Actor<AuthInterface>{service, accountRow->authService};
return Actor<AuthInterface>{service, to<Accounts>().getAuthOf(account)};
}

} // namespace SystemService
Expand Down
8 changes: 4 additions & 4 deletions services/system/AuthSig/src/AuthSig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ namespace SystemService
return;
}
}
abortMessage("transaction does not include a claim for the key " +
keyFingerprint(row->pubkey) + " needed to authenticate sender " +
sender.str() + " for action " + action.service.str() +
"::" + action.method.str());
abortMessage("transaction does not include a claim for the key "
+ keyFingerprint(row->pubkey) + " needed to authenticate sender "
+ sender.str() + " for action " + action.service.str()
+ "::" + action.method.str());
}

void AuthSig::canAuthUserSys(psibase::AccountNumber user)
Expand Down
Loading
Loading