transact

SystemService::Transact

struct SystemService::Transact {
    const psibase::AccountNumber service;      // "transact"
    const uint64_t               serviceFlags; // Flags this service must run with

    startBoot(...);      // This action enables the boot procedure to be split across multiple blocks
    finishBoot(...);     // Only called once during chain initialization
    startBlock(...);     // Called by native code at the beginning of each block
    runAs(...);          // Run `action` using `action.sender's` authority
    getTransaction(...); // Get the currently executing transaction
    currentBlock(...);   // Get the current block header
    headBlock(...);      // Get the head block header
    headBlockTime(...);  // Get the head block time
};

All transactions enter the chain through this service.

This privileged service dispatches top-level actions to other services, checks TAPoS, detects duplicate transactions, and checks authorizations using SystemService::AuthInterface.

Other services use it to get information about the chain, current block, and head block. They also use it to call actions using other accounts' authorities via runAs.

SystemService::Transact::startBoot

void SystemService::Transact::startBoot(
    psio::view<const std::vector<psibase::Checksum256>> bootTransactions
);

This action enables the boot procedure to be split across multiple blocks.

It is only called once, immediately after the boot transaction.

bootTransactions defines the list of subsequent transaction hashes to which the node operator is committing as part of the boot sequence. The subsequent transactions listed must then be pushed in order, and no other transactions will be accepted until finishBoot is run.

SystemService::Transact::finishBoot

void SystemService::Transact::finishBoot();

Only called once during chain initialization.

This enables the auth checking system. Before this point, Transact allows all transactions to execute without auth checks. After this point, Transact uses AuthInterface::checkAuthSys to authenticate top-level actions and uses of runAs.

SystemService::Transact::startBlock

void SystemService::Transact::startBlock();

Called by native code at the beginning of each block.

SystemService::Transact::runAs

std::vector<char> SystemService::Transact::runAs(
    psibase::Action            action,
    std::vector<ServiceMethod> allowedActions
);

Run action using action.sender's authority.

Also adds allowedActions to the list of actions that action.service may perform on action.sender's behalf, for as long as this call to runAs is in the call stack. Use "" for service in allowedActions to allow use of any service (danger!). Use "" for method to allow any method.

Returns the action's return value, if any.

This will succeed if any of the following are true:

  • getSender() == action.sender's authService
  • getSender() == action.sender. Requires action.sender's authService to approve with flag AuthInterface::runAsRequesterReq (normally succeeds).
  • An existing runAs is currently on the call stack, getSender() matches action.service on that earlier call, and action matches allowedActions from that same earlier call. Requires action.sender's authService to approve with flag AuthInterface::runAsMatchedReq if allowedActions is empty (normally succeeds), or AuthInterface::runAsMatchedExpandedReq if not empty (normally fails).
  • All other cases, requires action.sender's authService to approve with flag AuthInterface::runAsOtherReq (normally fails).

SystemService::Transact::getTransaction

psibase::Transaction SystemService::Transact::getTransaction() const;

Get the currently executing transaction.

SystemService::Transact::currentBlock

psibase::BlockHeader SystemService::Transact::currentBlock() const;

Get the current block header.

SystemService::Transact::headBlock

psibase::BlockHeader SystemService::Transact::headBlock() const;

Get the head block header.

This is not the currently executing block. See currentBlock.

SystemService::Transact::headBlockTime

psibase::TimePointSec SystemService::Transact::headBlockTime() const;

Get the head block time.

This is not the currently executing block time. TODO: remove

SystemService::ServiceMethod

struct SystemService::ServiceMethod {
    psibase::AccountNumber service; 
    psibase::MethodNumber  method;  
};

Identify a service and method.

An empty service or method indicates a wildcard.

SystemService::AuthInterface

struct SystemService::AuthInterface {
    const uint32_t readOnlyFlag;            // See header
    const uint32_t firstAuthFlag;           // See header
    const uint32_t requestMask;             // Bits which identify kind of request
    const uint32_t topActionReq;            // Top-level action
    const uint32_t runAsRequesterReq;       // See header
    const uint32_t runAsMatchedReq;         // See header
    const uint32_t runAsMatchedExpandedReq; // See header
    const uint32_t runAsOtherReq;           // See header

    checkAuthSys(...);   // Authenticate a top-level action or a `runAs` action
    canAuthUserSys(...); // Verify that a particular user is allowed to use a particular auth service. Allows auth services to use user whitelists.
};

Authenticate actions.

Transact calls into auth services using this interface to authenticate senders of top-level actions and uses of Transact::runAs. Any service may become an auth service by implementing AuthInterface. Any account may select any service to be its authenticator. Be careful; this allows that service to act on the account's behalf and that service to authorize other accounts and services to act on the account's behalf. It can also can lock out that account. See AuthK1 for a canonical example of implementing this interface.

This interface can't authenticate non-top-level actions other than Transact::runAs actions. Most services shouldn't call or implement AuthInterface; use getSender().

Auth services shouldn't inherit from this struct. Instead, they should define methods with matching signatures.

SystemService::AuthInterface::checkAuthSys

void SystemService::AuthInterface::checkAuthSys(
    uint32_t                    flags,
    psibase::AccountNumber      requester,
    psibase::AccountNumber      sender,
    ServiceMethod               action,
    std::vector<ServiceMethod>  allowedActions,
    std::vector<psibase::Claim> claims
);

Authenticate a top-level action or a runAs action.

  • flags: One of the Req (request) constants, or'ed with 0 or more of the flag constants
  • requester: "" if this is a top-level action, or the sender of the runAs action. This is often different from action.sender.
  • sender The sender being requested for the action.
  • action: Action to authenticate
  • allowedActions: Argument from runAs
  • claims: Claims in transaction (e.g. public keys). Empty if runAs

SystemService::AuthInterface::canAuthUserSys

void SystemService::AuthInterface::canAuthUserSys(
    psibase::AccountNumber user
);

Verify that a particular user is allowed to use a particular auth service. Allows auth services to use user whitelists..

Called by Accounts.

  • user: The user being checked