Documentation
¶
Index ¶
- Constants
- Variables
- func ConnectToDB(cnf DatabaseConfig, embedMigrations embed.FS) (*gorm.DB, error)
- func RegisterDBStatsCollector(db *gorm.DB, reg prometheus.Registerer) error
- func RegisterMetricsCallbacks(db *gorm.DB, obs QueryDurationObserver) error
- func SetupTestDB(t testing.TB) (*gorm.DB, func())
- type ActionLogEntryV1
- type ActiveCountByLabel
- type AppLedgerEntryV1
- type AppParticipantV1
- type AppSessionCount
- type AppSessionKeyAppSessionIDV1
- type AppSessionKeyApplicationV1
- type AppSessionKeyStateV1
- type AppSessionV1
- type AppV1
- type BlockchainAction
- type BlockchainActionStatus
- type BlockchainActionType
- type Channel
- type ChannelCount
- type ChannelSessionKeyAssetV1
- type ChannelSessionKeyStateV1
- type ContractEvent
- type CurrentSessionKeyStateV1
- type DBStore
- func (s *DBStore) CheckActiveChannel(wallet, asset string) (string, *core.ChannelStatus, error)
- func (s *DBStore) Complete(actionID int64, txHash string) error
- func (s *DBStore) CountActiveAppSessions(window time.Duration) ([]ActiveCountByLabel, error)
- func (s *DBStore) CountActiveUsers(window time.Duration) ([]ActiveCountByLabel, error)
- func (s *DBStore) CountSessionKeysForUser(userAddress string) (uint32, error)
- func (s *DBStore) CreateApp(entry app.AppV1) error
- func (s *DBStore) CreateAppSession(session app.AppSessionV1) error
- func (s *DBStore) CreateChannel(channel core.Channel) error
- func (s *DBStore) EnsureNoOngoingEscrowOperation(wallet, asset string) error
- func (s *DBStore) EnsureNoOngoingStateTransitions(wallet, asset string) error
- func (s *DBStore) ExecuteInTransaction(txFunc StoreTxHandler) error
- func (s *DBStore) Fail(actionID int64, err string) error
- func (s *DBStore) FailNoRetry(actionID int64, err string) error
- func (s *DBStore) GetActions(limit uint8, blockchainID uint64) ([]BlockchainAction, error)
- func (s *DBStore) GetActiveHomeChannel(wallet, asset string) (*core.Channel, error)
- func (s *DBStore) GetApp(appID string) (*app.AppInfoV1, error)
- func (s *DBStore) GetAppCount(ownerWallet string) (uint64, error)
- func (s *DBStore) GetAppSession(sessionID string) (*app.AppSessionV1, error)
- func (s *DBStore) GetAppSessionBalances(appSessionID string) (map[string]decimal.Decimal, error)
- func (s *DBStore) GetAppSessionKeyOwner(sessionKey, appSessionId, applicationId string) (string, error)
- func (s *DBStore) GetAppSessions(appSessionID *string, participant *string, status app.AppSessionStatus, ...) ([]app.AppSessionV1, core.PaginationMetadata, error)
- func (s *DBStore) GetAppSessionsCountByLabels() ([]AppSessionCount, error)
- func (s *DBStore) GetApps(appID *string, ownerWallet *string, pagination *core.PaginationParams) ([]app.AppInfoV1, core.PaginationMetadata, error)
- func (s *DBStore) GetChannelByID(channelID string) (*core.Channel, error)
- func (s *DBStore) GetChannelsCountByLabels() ([]ChannelCount, error)
- func (s *DBStore) GetLastAppSessionKeyState(wallet, sessionKey string) (*app.AppSessionKeyStateV1, error)
- func (s *DBStore) GetLastAppSessionKeyStates(wallet string, sessionKey *string, includeInactive bool, limit, offset uint32) ([]app.AppSessionKeyStateV1, uint32, error)
- func (s *DBStore) GetLastAppSessionKeyVersion(wallet, sessionKey string) (uint64, error)
- func (s *DBStore) GetLastChannelSessionKeyStates(wallet string, sessionKey *string, includeInactive bool, limit, offset uint32) ([]core.ChannelSessionKeyStateV1, uint32, error)
- func (s *DBStore) GetLastChannelSessionKeyVersion(wallet, sessionKey string) (uint64, error)
- func (s *DBStore) GetLastStateByChannelID(channelID string, signed bool) (*core.State, error)
- func (s *DBStore) GetLastUserState(wallet, asset string, signed bool) (*core.State, error)
- func (s *DBStore) GetLatestContractEventBlockNumber(contractAddress string, blockchainID uint64) (uint64, error)
- func (s *DBStore) GetLifetimeMetricLastTimestamp(name string) (time.Time, error)
- func (s *DBStore) GetNodeBalance() ([]NodeBalance, error)
- func (s *DBStore) GetNotClosedHomeChannel(wallet, asset string) (*core.Channel, error)
- func (s *DBStore) GetParticipantAllocations(appSessionID string) (map[string]map[string]decimal.Decimal, error)
- func (s *DBStore) GetStateByChannelIDAndVersion(channelID string, version uint64) (*core.State, error)
- func (s *DBStore) GetStateByID(stateID string) (*core.State, error)
- func (s *DBStore) GetTotalUserStaked(wallet string) (decimal.Decimal, error)
- func (s *DBStore) GetTotalValueLocked() ([]TotalValueLocked, error)
- func (s *DBStore) GetUserActionCount(wallet string, gatedAction core.GatedAction, window time.Duration) (uint64, error)
- func (s *DBStore) GetUserActionCounts(userWallet string, window time.Duration) (map[core.GatedAction]uint64, error)
- func (s *DBStore) GetUserBalanceSummary() ([]UserBalanceSummary, error)
- func (s *DBStore) GetUserBalances(wallet string) ([]core.BalanceEntry, error)
- func (s *DBStore) GetUserChannels(wallet string, status *core.ChannelStatus, asset *string, ...) ([]core.Channel, uint32, error)
- func (s *DBStore) GetUserTransactions(accountID string, asset *string, txType *core.TransactionType, ...) ([]core.Transaction, core.PaginationMetadata, error)
- func (s *DBStore) HasNonClosedHomeChannel(wallet, asset string) (bool, error)
- func (s *DBStore) HasSignedFinalize(channelID string) (bool, error)
- func (s *DBStore) IsContractEventPresent(blockchainID, blockNumber uint64, txHash string, logIndex uint32) (bool, error)
- func (s *DBStore) LockSessionKeyState(userAddress, sessionKey string, kind SessionKeyKind) (uint64, time.Time, error)
- func (s *DBStore) LockUserState(wallet, asset string) (decimal.Decimal, error)
- func (s *DBStore) RecordAction(wallet string, gatedAction core.GatedAction) error
- func (s *DBStore) RecordAttempt(actionID int64, err string) error
- func (s *DBStore) RecordLedgerEntry(userWallet, accountID, asset string, amount decimal.Decimal) error
- func (s *DBStore) RecordTransaction(tx core.Transaction, applicationID string) error
- func (s *DBStore) RefreshUserEnforcedBalance(wallet, asset string) error
- func (s *DBStore) ScheduleChallenge(stateID string, blockchainID uint64) error
- func (s *DBStore) ScheduleCheckpoint(stateID string, blockchainID uint64) error
- func (s *DBStore) ScheduleFinalizeEscrowDeposit(stateID string, blockchainID uint64) error
- func (s *DBStore) ScheduleFinalizeEscrowWithdrawal(stateID string, blockchainID uint64) error
- func (s *DBStore) ScheduleInitiateEscrowDeposit(stateID string, blockchainID uint64) error
- func (s *DBStore) ScheduleInitiateEscrowWithdrawal(stateID string, blockchainID uint64) error
- func (s *DBStore) SetNodeBalance(blockchainID uint64, asset string, value decimal.Decimal) error
- func (s *DBStore) StoreAppSessionKeyState(state app.AppSessionKeyStateV1) error
- func (s *DBStore) StoreChannelSessionKeyState(state core.ChannelSessionKeyStateV1) error
- func (s *DBStore) StoreContractEvent(ev core.BlockchainEvent) error
- func (s *DBStore) StoreUserState(state core.State, applicationID string) error
- func (s *DBStore) SumNetTransitionAmountAfterVersion(channelID string, minVersion uint64) (decimal.Decimal, error)
- func (s *DBStore) UpdateAppSession(session app.AppSessionV1) error
- func (s *DBStore) UpdateChannel(channel core.Channel) error
- func (s *DBStore) UpdateStateSigsIfMissing(channelID string, version uint64, userSig, nodeSig string) error
- func (s *DBStore) UpdateUserStaked(wallet string, blockchainID uint64, amount decimal.Decimal) error
- func (s *DBStore) ValidateChannelSessionKeyForAsset(wallet, sessionKey, asset, metadataHash string) (bool, error)
- type DatabaseConfig
- type DatabaseStore
- type LifespanMetric
- type ListOptions
- type NodeBalance
- type QueryDurationObserver
- type SessionKeyKind
- type SortType
- type State
- type StoreTxHandler
- type TotalValueLocked
- type Transaction
- type UserBalance
- type UserBalanceSummary
- type UserStakedV1
Constants ¶
const ( ErrGetAccountBalance = "failed to get account balance" ErrRecordLedgerEntry = "failed to record a ledger entry" )
const ( DefaultLimit = 10 MaxLimit = 100 )
Variables ¶
var ( ErrInvalidLedgerTransactionType = "invalid ledger transaction type" ErrRecordTransaction = "failed to record transaction" )
var ErrEventHasAlreadyBeenProcessed = errors.New("contract event has already been processed")
var ErrSessionKeyNotAllowed = errors.New("session key not allowed")
ErrSessionKeyNotAllowed is returned by LockSessionKeyState when the session key for the requested kind is bound to a wallet other than the submitter. The message is intentionally generic so the API does not confirm whether a given session_key is registered elsewhere.
Functions ¶
func ConnectToDB ¶
func RegisterDBStatsCollector ¶
func RegisterDBStatsCollector(db *gorm.DB, reg prometheus.Registerer) error
RegisterDBStatsCollector registers the standard go_sql_* collector on reg for the underlying *sql.DB, so pool-state gauges and wait counters become scrapable. Returns an error if the gorm DB doesn't expose a *sql.DB (sqlite-in-memory variants normally do; misconfigured pools don't).
Emits, under "nitronode" db name:
go_sql_max_open_connections go_sql_open_connections go_sql_in_use_connections go_sql_idle_connections go_sql_wait_count_total go_sql_wait_duration_seconds_total go_sql_max_idle_closed_total go_sql_max_idle_time_closed_total go_sql_max_lifetime_closed_total
func RegisterMetricsCallbacks ¶
func RegisterMetricsCallbacks(db *gorm.DB, obs QueryDurationObserver) error
RegisterMetricsCallbacks installs gorm callbacks that observe wall-clock duration of each Create / Query / Update / Delete / Row / Raw operation onto obs. Pass nil to skip registration (test / sqlite-in-memory cases).
The callbacks add no per-call allocation beyond a single time.Time stashed in the gorm context dict.
Types ¶
type ActionLogEntryV1 ¶
type ActionLogEntryV1 struct {
ID uuid.UUID `gorm:"type:char(36);primaryKey"`
UserWallet string `gorm:"column:user_wallet;not null"`
GatedAction uint8 `gorm:"column:gated_action;not null"`
CreatedAt time.Time
}
func (ActionLogEntryV1) TableName ¶
func (ActionLogEntryV1) TableName() string
type ActiveCountByLabel ¶
type ActiveCountByLabel struct {
Label string `gorm:"column:label"`
Count uint64 `gorm:"column:count"`
}
CountActiveUsers returns the number of distinct users who had channel state updates within the given duration, grouped by asset. If asset is empty, counts across all assets. ActiveCountByLabel holds a count grouped by a label (asset or application_id).
type AppLedgerEntryV1 ¶
type AppLedgerEntryV1 struct {
ID uuid.UUID `gorm:"type:char(36);primaryKey"`
AccountID string `gorm:"column:account_id;not null;index:idx_account_asset_symbol;index:idx_account_wallet"`
AssetSymbol string `gorm:"column:asset_symbol;not null;index:idx_account_asset_symbol"`
Wallet string `gorm:"column:wallet;not null;index:idx_account_wallet"`
Credit decimal.Decimal `gorm:"column:credit;type:varchar(78);not null"`
Debit decimal.Decimal `gorm:"column:debit;type:varchar(78);not null"`
CreatedAt time.Time
}
AppLedgerEntryV1 represents a ledger entry in the database
func (AppLedgerEntryV1) TableName ¶
func (AppLedgerEntryV1) TableName() string
type AppParticipantV1 ¶
type AppParticipantV1 struct {
AppSessionID string `gorm:"column:app_session_id;not null;primaryKey;priority:1"`
WalletAddress string `gorm:"column:wallet_address;not null;primaryKey;priority:2"`
SignatureWeight uint8 `gorm:"column:signature_weight;not null"`
}
AppParticipantV1 represents the definition for an app participant.
func (AppParticipantV1) TableName ¶
func (AppParticipantV1) TableName() string
type AppSessionCount ¶
type AppSessionCount struct {
Application string `gorm:"column:application_id"`
Status app.AppSessionStatus `gorm:"column:status"`
Count uint64 `gorm:"column:count"`
}
AppSessionCount holds the result of a COUNT() GROUP BY query on app sessions.
type AppSessionKeyAppSessionIDV1 ¶
type AppSessionKeyAppSessionIDV1 struct {
SessionKeyStateID string `gorm:"column:session_key_state_id;not null;primaryKey;priority:1"`
AppSessionID string `gorm:"column:app_session_id;not null;primaryKey;priority:2;index"`
}
AppSessionKeyAppSessionIDV1 links a session key state to an app session ID.
func (AppSessionKeyAppSessionIDV1) TableName ¶
func (AppSessionKeyAppSessionIDV1) TableName() string
type AppSessionKeyApplicationV1 ¶
type AppSessionKeyApplicationV1 struct {
SessionKeyStateID string `gorm:"column:session_key_state_id;not null;primaryKey;priority:1"`
ApplicationID string `gorm:"column:application_id;not null;primaryKey;priority:2;index"`
}
SessionKeyApplicationV1 links a session key state to an application ID.
func (AppSessionKeyApplicationV1) TableName ¶
func (AppSessionKeyApplicationV1) TableName() string
type AppSessionKeyStateV1 ¶
type AppSessionKeyStateV1 struct {
ID string `gorm:"column:id;primaryKey"`
UserAddress string `gorm:"column:user_address;not null;uniqueIndex:idx_session_key_states_v1_user_key_ver,priority:1"`
SessionKey string `gorm:"column:session_key;not null;uniqueIndex:idx_session_key_states_v1_user_key_ver,priority:2"`
Version uint64 `gorm:"column:version;not null;uniqueIndex:idx_session_key_states_v1_user_key_ver,priority:3"`
ApplicationIDs []AppSessionKeyApplicationV1 `gorm:"foreignKey:SessionKeyStateID;references:ID"`
AppSessionIDs []AppSessionKeyAppSessionIDV1 `gorm:"foreignKey:SessionKeyStateID;references:ID"`
ExpiresAt time.Time `gorm:"column:expires_at;not null"`
UserSig string `gorm:"column:user_sig;not null"`
SessionKeySig string `gorm:"column:session_key_sig"`
CreatedAt time.Time
}
AppSessionKeyStateV1 represents a session key state in the database. ID is Hash(user_address + session_key + version).
func (AppSessionKeyStateV1) TableName ¶
func (AppSessionKeyStateV1) TableName() string
type AppSessionV1 ¶
type AppSessionV1 struct {
ID string `gorm:"primaryKey"`
ApplicationID string `gorm:"column:application_id;not null"`
Nonce uint64 `gorm:"column:nonce;not null"`
Participants []AppParticipantV1 `gorm:"foreignKey:AppSessionID;references:ID"`
SessionData string `gorm:"column:session_data;type:text;not null"`
Quorum uint8 `gorm:"column:quorum;default:100"`
Version uint64 `gorm:"column:version;default:1"`
Status app.AppSessionStatus `gorm:"column:status;not null"`
CreatedAt time.Time
UpdatedAt time.Time
}
AppSessionV1 represents a virtual payment application session between participants
func (AppSessionV1) TableName ¶
func (AppSessionV1) TableName() string
type AppV1 ¶
type AppV1 struct {
ID string `gorm:"primaryKey"`
OwnerWallet string `gorm:"column:owner_wallet;not null"`
Metadata string `gorm:"column:metadata;type:text;not null"`
Version uint64 `gorm:"column:version;default:1"`
CreationApprovalNotRequired bool `gorm:"column:creation_approval_not_required"`
CreatedAt time.Time
UpdatedAt time.Time
}
AppV1 represents an application registry entry in the database.
type BlockchainAction ¶
type BlockchainAction struct {
ID int64 `gorm:"primary_key"`
Type BlockchainActionType `gorm:"column:action_type;not null"`
StateID string `gorm:"column:state_id;size:66"`
BlockchainID uint64 `gorm:"column:blockchain_id;not null"`
Data datatypes.JSON `gorm:"column:action_data;type:text"`
Status BlockchainActionStatus `gorm:"column:status;not null"`
Retries uint8 `gorm:"column:retry_count;default:0"`
Error string `gorm:"column:last_error;type:text"`
TxHash string `gorm:"column:transaction_hash;size:66"`
CreatedAt time.Time `gorm:"column:created_at"`
UpdatedAt time.Time `gorm:"column:updated_at"`
}
func (BlockchainAction) TableName ¶
func (BlockchainAction) TableName() string
type BlockchainActionStatus ¶
type BlockchainActionStatus uint8
const ( BlockchainActionStatusPending BlockchainActionStatus = iota BlockchainActionStatusCompleted BlockchainActionStatusFailed )
type BlockchainActionType ¶
type BlockchainActionType uint8
const ( ActionTypeCheckpoint BlockchainActionType = 1 ActionTypeChallenge BlockchainActionType = 2 ActionTypeInitiateEscrowDeposit BlockchainActionType = 10 ActionTypeFinalizeEscrowDeposit BlockchainActionType = 11 ActionTypeInitiateEscrowWithdrawal BlockchainActionType = 20 ActionTypeFinalizeEscrowWithdrawal BlockchainActionType = 21 )
func (BlockchainActionType) String ¶
func (t BlockchainActionType) String() string
type Channel ¶
type Channel struct {
ChannelID string `gorm:"column:channel_id;primaryKey;"`
UserWallet string `gorm:"column:user_wallet;not null"`
Asset string `gorm:"column:asset;not null"`
Type core.ChannelType `gorm:"column:type;not null"`
BlockchainID uint64 `gorm:"column:blockchain_id;not null"`
Token string `gorm:"column:token;not null"`
ChallengeDuration uint32 `gorm:"column:challenge_duration;not null"`
ChallengeExpiresAt *time.Time `gorm:"column:challenge_expires_at;default:null"`
Nonce uint64 `gorm:"column:nonce;not null;"`
ApprovedSigValidators string `gorm:"column:approved_sig_validators;not null;"`
Status core.ChannelStatus `gorm:"column:status;not null;"`
StateVersion uint64 `gorm:"column:state_version;not null;"`
CreatedAt time.Time
UpdatedAt time.Time
}
Channel represents a state channel between participants
type ChannelCount ¶
type ChannelCount struct {
Asset string `gorm:"column:asset"`
Status core.ChannelStatus `gorm:"column:status"`
Count uint64 `gorm:"column:count"`
}
ChannelCount holds the result of a COUNT() GROUP BY query on channels.
type ChannelSessionKeyAssetV1 ¶
type ChannelSessionKeyAssetV1 struct {
SessionKeyStateID string `gorm:"column:session_key_state_id;not null;primaryKey;priority:1"`
Asset string `gorm:"column:asset;not null;primaryKey;priority:2;index"`
}
ChannelSessionKeyAssetV1 links a channel session key state to an asset.
func (ChannelSessionKeyAssetV1) TableName ¶
func (ChannelSessionKeyAssetV1) TableName() string
type ChannelSessionKeyStateV1 ¶
type ChannelSessionKeyStateV1 struct {
ID string `gorm:"column:id;primaryKey"`
UserAddress string `gorm:"column:user_address;not null;uniqueIndex:idx_channel_session_key_states_v1_user_key_ver,priority:1"`
SessionKey string `gorm:"column:session_key;not null;uniqueIndex:idx_channel_session_key_states_v1_user_key_ver,priority:2"`
Version uint64 `gorm:"column:version;not null;uniqueIndex:idx_channel_session_key_states_v1_user_key_ver,priority:3"`
Assets []ChannelSessionKeyAssetV1 `gorm:"foreignKey:SessionKeyStateID;references:ID"`
MetadataHash string `gorm:"column:metadata_hash;type:char(66);not null"`
ExpiresAt time.Time `gorm:"column:expires_at;not null"`
UserSig string `gorm:"column:user_sig;not null"`
SessionKeySig string `gorm:"column:session_key_sig"`
CreatedAt time.Time
}
ChannelSessionKeyStateV1 represents a channel session key state in the database.
func (ChannelSessionKeyStateV1) TableName ¶
func (ChannelSessionKeyStateV1) TableName() string
type ContractEvent ¶
type ContractEvent struct {
ID int64 `gorm:"primary_key;column:id"`
ContractAddress string `gorm:"column:contract_address"`
BlockchainID uint64 `gorm:"column:blockchain_id"`
Name string `gorm:"column:name"`
BlockNumber uint64 `gorm:"column:block_number"`
TransactionHash string `gorm:"column:transaction_hash"`
LogIndex uint32 `gorm:"column:log_index"`
CreatedAt time.Time `gorm:"column:created_at"`
}
func (ContractEvent) TableName ¶
func (ContractEvent) TableName() string
type CurrentSessionKeyStateV1 ¶
type CurrentSessionKeyStateV1 struct {
UserAddress string `gorm:"column:user_address;primaryKey;size:42"`
SessionKey string `gorm:"column:session_key;primaryKey;size:42;uniqueIndex:current_session_key_states_v1_key_kind_uniq,priority:1"`
Kind SessionKeyKind `gorm:"column:kind;primaryKey;type:smallint;uniqueIndex:current_session_key_states_v1_key_kind_uniq,priority:2"`
Version uint64 `gorm:"column:version;not null"`
UpdatedAt time.Time `gorm:"column:updated_at"`
}
CurrentSessionKeyStateV1 is the latest-version pointer per (user_address, session_key, kind). Reads of get_last_key_states JOIN this table to the corresponding history table (channel_session_key_states_v1 or app_session_key_states_v1) on (user_address, session_key, version), bounding per-request DB work to O(distinct keys).
The uniqueIndex on (session_key, kind) mirrors the postgres constraint added by 20260508000000_session_key_ownership_constraints.sql so AutoMigrate (sqlite) enforces the same one-owner-per-key invariant that LockSessionKeyState relies on. The index name matches the postgres constraint name so both paths converge on a single source of truth.
func (CurrentSessionKeyStateV1) TableName ¶
func (CurrentSessionKeyStateV1) TableName() string
type DBStore ¶
type DBStore struct {
// contains filtered or unexported fields
}
func (*DBStore) CheckActiveChannel ¶
CheckActiveChannel verifies if a user has an active home channel for the given asset and returns its approved signature validators along with the channel status. "Active" includes Void (DB-only, awaiting onchain confirmation) and Open (materialized onchain). This is intentional: non-escrow offchain transitions (transfers, etc.) are permitted before onchain confirmation lands. Callers operating on cross-chain escrow flows that depend on onchain home-channel materialization must check that the returned status is ChannelStatusOpen.
A nil status pointer means no active channel was found.
func (*DBStore) CountActiveAppSessions ¶
func (s *DBStore) CountActiveAppSessions(window time.Duration) ([]ActiveCountByLabel, error)
CountActiveAppSessions returns app session counts per application within the given window.
func (*DBStore) CountActiveUsers ¶
func (s *DBStore) CountActiveUsers(window time.Duration) ([]ActiveCountByLabel, error)
CountActiveUsers returns distinct user counts per asset and an "all" aggregate for users with channel state updates within the given window.
func (*DBStore) CountSessionKeysForUser ¶
CountSessionKeysForUser returns the number of distinct active session keys recorded for the wallet in the pointer table, across both kinds. Drives the per-user cap at submit time. Rows seeded by LockSessionKeyState (version=0) are excluded so that a failed-cap rejection does not itself leave a phantom row counted toward the cap. Revoked or naturally expired keys (expires_at <= now in the underlying history row) are also excluded so that a revoke frees the slot. A single now is bound for both kind branches so the count is internally consistent.
func (*DBStore) CreateApp ¶
CreateApp registers a new application. Returns an error if the app ID already exists.
func (*DBStore) CreateAppSession ¶
func (s *DBStore) CreateAppSession(session app.AppSessionV1) error
CreateAppSession initializes a new application session.
func (*DBStore) CreateChannel ¶
CreateChannel creates a new channel entity in the database.
func (*DBStore) EnsureNoOngoingEscrowOperation ¶
EnsureNoOngoingEscrowOperation validates that the user has no in-flight escrow operation that would prevent the node from issuing receiver-side states (transfer receive, app-session release).
Validation logic by latest signed transition type:
- escrow_lock / mutual_lock: always considered ongoing (no finalization yet)
- escrow_deposit: considered settled when the on-chain escrow channel version equals the signed state version (finalize landed). When the chain is exactly one behind, the signed N+1 finalize state lives off-chain and is gated on the escrow channel status: allowed for Open (protocol-intended steady state before the purge queue fires) and Closed (post-purge or post-finalize); blocked for Challenged (on-chain resolution still racing — finalize tx may not land, escrow chain may settle at INITIATE, and replaying N+1 later could violate engine invariants).
- escrow_withdraw: considered ongoing while the on-chain escrow channel state version has not caught up with the signed state version
- any other transition: not an escrow operation, allow
func (*DBStore) EnsureNoOngoingStateTransitions ¶
EnsureNoOngoingStateTransitions validates that no conflicting blockchain operations are pending. This method prevents race conditions by ensuring blockchain state versions match the user's last signed state version before accepting new transitions.
Validation logic by transition type:
- home_deposit: Verify last_state.version == home_channel.state_version
- mutual_lock: Verify last_state.version == home_channel.state_version == escrow_channel.state_version AND next transition must be escrow_deposit
- escrow_lock: Verify last_state.version == escrow_channel.state_version AND next transition must be escrow_withdraw or migrate
- escrow_withdraw: Verify last_state.version == escrow_channel.state_version
- migrate: Verify last_state.version == home_channel.state_version
func (*DBStore) ExecuteInTransaction ¶
func (s *DBStore) ExecuteInTransaction(txFunc StoreTxHandler) error
func (*DBStore) GetActions ¶
func (s *DBStore) GetActions(limit uint8, blockchainID uint64) ([]BlockchainAction, error)
func (*DBStore) GetActiveHomeChannel ¶
GetActiveHomeChannel retrieves the active home channel for a user's wallet and asset. "Active" means the node has co-signed the channel definition (status Void or Open) — it does NOT guarantee the channel has been materialized onchain. Callers requiring onchain materialization (e.g., cross-chain escrow operations) must additionally check that Status == ChannelStatusOpen.
func (*DBStore) GetAppSession ¶
func (s *DBStore) GetAppSession(sessionID string) (*app.AppSessionV1, error)
GetAppSession retrieves a specific session by ID.
func (*DBStore) GetAppSessionBalances ¶
GetAppSessionBalances retrieves the total balances associated with a session.
func (*DBStore) GetAppSessionKeyOwner ¶
func (s *DBStore) GetAppSessionKeyOwner(sessionKey, appSessionId, applicationId string) (string, error)
GetAppSessionKeyOwner returns the user_address that owns the given session key authorized for the specified app session ID or application ID. Only the latest-version, non-expired key with matching permissions is considered. A newer version always supersedes older ones.
Both appSessionId and applicationId are accepted because the app session row may not yet exist in the database when this is called (notably during app session creation). Passing applicationId directly avoids a chicken-and-egg subquery against the not-yet-inserted row; callers always know the application ID either from the signed request (create) or from the loaded app session record (post-create state updates).
func (*DBStore) GetAppSessions ¶
func (s *DBStore) GetAppSessions(appSessionID *string, participant *string, status app.AppSessionStatus, pagination *core.PaginationParams) ([]app.AppSessionV1, core.PaginationMetadata, error)
GetAppSessions retrieves filtered sessions with pagination.
func (*DBStore) GetAppSessionsCountByLabels ¶
func (s *DBStore) GetAppSessionsCountByLabels() ([]AppSessionCount, error)
GetAppSessionsCountByLabels returns current app session counts grouped by application and status.
func (*DBStore) GetApps ¶
func (s *DBStore) GetApps(appID *string, ownerWallet *string, pagination *core.PaginationParams) ([]app.AppInfoV1, core.PaginationMetadata, error)
GetApps retrieves applications with optional filtering by app ID, owner wallet, and pagination.
func (*DBStore) GetChannelByID ¶
GetChannelByID retrieves a channel by its unique identifier.
func (*DBStore) GetChannelsCountByLabels ¶
func (s *DBStore) GetChannelsCountByLabels() ([]ChannelCount, error)
GetChannelsCountByLabels returns current channel counts grouped by asset and status.
func (*DBStore) GetLastAppSessionKeyState ¶
func (s *DBStore) GetLastAppSessionKeyState(wallet, sessionKey string) (*app.AppSessionKeyStateV1, error)
GetLastAppSessionKeyState retrieves the latest version of a specific session key for a user. A newer version always supersedes older ones, even if expired. Resolved via the pointer table; returns nil if no state exists.
func (*DBStore) GetLastAppSessionKeyStates ¶
func (s *DBStore) GetLastAppSessionKeyStates(wallet string, sessionKey *string, includeInactive bool, limit, offset uint32) ([]app.AppSessionKeyStateV1, uint32, error)
GetLastAppSessionKeyStates retrieves the latest session key states for a user with optional filtering. Reads filter the current_session_key_states_v1 pointer table by (user_address, kind=app_session) and JOIN history on (user_address, session_key, version). Per-request DB work is bounded by the number of distinct session keys for the user, regardless of version churn in history. When includeInactive is false the same now is applied to both the count and the list query so pagination stays consistent across the two reads. Results are paginated; totalCount is the unpaginated total of matching session keys.
func (*DBStore) GetLastAppSessionKeyVersion ¶
GetLastAppSessionKeyVersion returns the latest version of a session key state for a user. Reads from the pointer table; returns 0 if no state exists or the pointer is at its seeded value (LockSessionKeyState created the row but no submit has succeeded yet).
func (*DBStore) GetLastChannelSessionKeyStates ¶
func (s *DBStore) GetLastChannelSessionKeyStates(wallet string, sessionKey *string, includeInactive bool, limit, offset uint32) ([]core.ChannelSessionKeyStateV1, uint32, error)
GetLastChannelSessionKeyStates retrieves the latest channel session key states for a user with optional filtering. Reads filter the current_session_key_states_v1 pointer table by (user_address, kind=channel) and JOIN history on (user_address, session_key, version). Per-request DB work is bounded by the number of distinct session keys for the user, regardless of version churn in history. When includeInactive is false the same now is applied to both the count and the list query so pagination stays consistent across the two reads. Results are paginated; totalCount is the unpaginated total of matching session keys.
func (*DBStore) GetLastChannelSessionKeyVersion ¶
GetLastChannelSessionKeyVersion returns the latest version of a channel session key state. Reads from the pointer table; returns 0 if no state exists or the pointer is at its seeded value (LockSessionKeyState created the row but no submit has succeeded yet).
func (*DBStore) GetLastStateByChannelID ¶
GetLastStateByChannelID retrieves the most recent state for a given channel. Uses UNION ALL of two indexed queries instead of OR for better performance.
func (*DBStore) GetLastUserState ¶
GetLastUserState retrieves the most recent state for a user's asset.
func (*DBStore) GetLatestContractEventBlockNumber ¶
func (s *DBStore) GetLatestContractEventBlockNumber(contractAddress string, blockchainID uint64) (uint64, error)
GetLatestContractEventBlockNumber returns the highest block number stored for a given contract.
func (*DBStore) GetLifetimeMetricLastTimestamp ¶
GetLifetimeMetricLastTimestamp returns the most recent last_timestamp among all metrics with the given name.
func (*DBStore) GetNodeBalance ¶
func (s *DBStore) GetNodeBalance() ([]NodeBalance, error)
GetNodeBalance returns the on-chain liquidity per blockchain and asset.
func (*DBStore) GetNotClosedHomeChannel ¶
GetNotClosedHomeChannel retrieves the home channel for a user's wallet and asset as long as it has not reached ChannelStatusClosed. This is broader than GetActiveHomeChannel (which stops at Open) and is intended for read paths that must remain functional after an off-chain Finalize, such as fetching channel data before submitting an on-chain close.
func (*DBStore) GetParticipantAllocations ¶
func (s *DBStore) GetParticipantAllocations(appSessionID string) (map[string]map[string]decimal.Decimal, error)
GetParticipantAllocations retrieves specific asset allocations per participant. This will only return participants who have non-zero balances.
func (*DBStore) GetStateByChannelIDAndVersion ¶
func (s *DBStore) GetStateByChannelIDAndVersion(channelID string, version uint64) (*core.State, error)
GetStateByChannelIDAndVersion retrieves a specific state version for a channel. Uses UNION ALL of two indexed queries instead of OR for better performance.
func (*DBStore) GetStateByID ¶
GetStateByID retrieves a state by its deterministic ID.
func (*DBStore) GetTotalUserStaked ¶
GetTotalUserStaked returns the total staked amount for a user across all blockchains.
func (*DBStore) GetTotalValueLocked ¶
func (s *DBStore) GetTotalValueLocked() ([]TotalValueLocked, error)
func (*DBStore) GetUserActionCount ¶
func (s *DBStore) GetUserActionCount(wallet string, gatedAction core.GatedAction, window time.Duration) (uint64, error)
GetUserActionCount returns the number of actions matching the given wallet and gated action within the specified time window (counting backwards from now).
func (*DBStore) GetUserActionCounts ¶
func (*DBStore) GetUserBalanceSummary ¶
func (s *DBStore) GetUserBalanceSummary() ([]UserBalanceSummary, error)
GetUserBalanceSummary returns off-chain liquidity metrics per blockchain and asset. Results include rows with home_blockchain_id = 0, representing balances not yet associated with a home blockchain — useful for surfacing funds that aren't attributed to any specific chain.
func (*DBStore) GetUserBalances ¶
func (s *DBStore) GetUserBalances(wallet string) ([]core.BalanceEntry, error)
GetUserBalances retrieves the balances for a user's wallet.
func (*DBStore) GetUserChannels ¶
func (s *DBStore) GetUserChannels(wallet string, status *core.ChannelStatus, asset *string, channelType *core.ChannelType, limit, offset uint32) ([]core.Channel, uint32, error)
GetUserChannels retrieves all channels for a user with optional status, asset, and type filters.
func (*DBStore) GetUserTransactions ¶
func (s *DBStore) GetUserTransactions(accountID string, asset *string, txType *core.TransactionType, fromTime *uint64, toTime *uint64, paginate *core.PaginationParams) ([]core.Transaction, core.PaginationMetadata, error)
GetUserTransactions retrieves transaction history for a user with optional filters.
func (*DBStore) HasNonClosedHomeChannel ¶
HasNonClosedHomeChannel returns true if any home channel for (wallet, asset) has a status other than Closed, meaning a channel lifecycle is still in progress.
func (*DBStore) HasSignedFinalize ¶
HasSignedFinalize reports whether a node-signed Finalize state exists for the given home channel. Used by event handlers to detect the post-Finalize lifecycle without loading the state row: the channels.status field can be temporarily overwritten by Challenged on a stale on-chain challenge, but the Finalize row persists here and is the authoritative marker. node_sig IS NOT NULL is checked explicitly so the contract holds even if a future path ever stores a Finalize row before the node signs.
func (*DBStore) IsContractEventPresent ¶
func (s *DBStore) IsContractEventPresent(blockchainID, blockNumber uint64, txHash string, logIndex uint32) (bool, error)
IsContractEventPresent checks whether a specific contract event has already been stored.
func (*DBStore) LockSessionKeyState ¶
func (s *DBStore) LockSessionKeyState(userAddress, sessionKey string, kind SessionKeyKind) (uint64, time.Time, error)
LockSessionKeyState seeds the pointer row for (userAddress, session_key, kind) if absent and locks the (session_key, kind) row for the surrounding transaction. Returns the latest stored version for the caller's row, or ErrSessionKeyNotAllowed if the key is bound to a different wallet for this kind.
The (session_key, kind) unique constraint guarantees there is at most one pointer row per (session_key, kind), so the SELECT ... FOR UPDATE that follows the no-op-on-conflict insert always converges on the same physical row regardless of who tried to seed first. A foreign wallet that races a legitimate owner ends up reading the legitimate owner back from the locked row and is rejected here, without parsing constraint-violation errors at write time.
SELECT ... FOR UPDATE is postgres-only; on sqlite the locking clause is skipped and the surrounding transaction provides the necessary ordering for the in-process test setup.
Seed-row permanence: the version=0 row written below is intentionally never deleted on failure paths (sig validation, version mismatch, cap exceeded, mid-tx errors). Once a wallet has staked a claim on (session_key, kind), no other wallet can take it for that kind — the seed is the ownership reservation, not a transient placeholder. CountSessionKeysForUser excludes version=0 rows so the per-user cap is unaffected, but the (session_key, kind) ownership bind is permanent by design.
When locked.Version > 0, the matching history row's expires_at is also returned so callers can distinguish a reactivation (prev inactive → submitted active) from a rotation/update (prev still active) and re-run the per-user cap on the reactivation path. When locked.Version == 0 there is no history yet, so a zero time.Time is returned.
func (*DBStore) LockUserState ¶
LockUserState locks a user's balance row for update (postgres only, must be used within a transaction). Uses INSERT ... ON CONFLICT DO NOTHING to ensure the row exists, then SELECT ... FOR UPDATE to lock it. Returns the current balance or zero if the row was just inserted.
func (*DBStore) RecordAction ¶
func (s *DBStore) RecordAction(wallet string, gatedAction core.GatedAction) error
RecordAction inserts a new action log entry for a user.
func (*DBStore) RecordLedgerEntry ¶
func (s *DBStore) RecordLedgerEntry(userWallet, accountID, asset string, amount decimal.Decimal) error
RecordLedgerEntry logs a movement of funds within the internal ledger.
func (*DBStore) RecordTransaction ¶
func (s *DBStore) RecordTransaction(tx core.Transaction, applicationID string) error
RecordTransaction creates a transaction record linking state transitions. applicationID is the client-declared origin tag; empty string → NULL column.
func (*DBStore) RefreshUserEnforcedBalance ¶
RefreshUserEnforcedBalance recomputes the enforced balance from the user's open home channel on-chain state.
func (*DBStore) ScheduleChallenge ¶
ScheduleChallenge queues a blockchain action to challenge a channel on its home blockchain using the provided state. The worker submits the state via challengeChannel(...) with a node-produced challenger signature.
func (*DBStore) ScheduleCheckpoint ¶
ScheduleCheckpoint queues a blockchain action to checkpoint a state on home blockchain.
func (*DBStore) ScheduleFinalizeEscrowDeposit ¶
ScheduleFinalizeEscrowDeposit schedules a finalize for an escrow deposit operation on non-home blockchain.
func (*DBStore) ScheduleFinalizeEscrowWithdrawal ¶
ScheduleFinalizeEscrowWithdrawal schedules a finalize for an escrow withdrawal operation on non-home blockchain.
func (*DBStore) ScheduleInitiateEscrowDeposit ¶
ScheduleInitiateEscrowDeposit queues a blockchain action to initiate escrow deposit on home blockchain.
func (*DBStore) ScheduleInitiateEscrowWithdrawal ¶
ScheduleInitiateEscrowWithdrawal queues a blockchain action to initiate withdrawal on non-home blockchain.
func (*DBStore) SetNodeBalance ¶
SetNodeBalance upserts the on-chain liquidity for a given blockchain and asset.
func (*DBStore) StoreAppSessionKeyState ¶
func (s *DBStore) StoreAppSessionKeyState(state app.AppSessionKeyStateV1) error
StoreAppSessionKeyState stores a new session key state version.
func (*DBStore) StoreChannelSessionKeyState ¶
func (s *DBStore) StoreChannelSessionKeyState(state core.ChannelSessionKeyStateV1) error
StoreChannelSessionKeyState stores a new channel session key state version.
func (*DBStore) StoreContractEvent ¶
func (s *DBStore) StoreContractEvent(ev core.BlockchainEvent) error
StoreContractEvent stores a blockchain event to the database. This function matches the signature required by pkg/blockchain/evm.StoreContractEvent.
func (*DBStore) StoreUserState ¶
StoreUserState persists a new user state to the database. applicationID is the client-declared origin tag; empty string → NULL column.
func (*DBStore) SumNetTransitionAmountAfterVersion ¶
func (s *DBStore) SumNetTransitionAmountAfterVersion(channelID string, minVersion uint64) (decimal.Decimal, error)
SumNetTransitionAmountAfterVersion returns the net effect on the user's home-channel balance of transitions stored against channelID strictly above minVersion. Receiver credits (TransferReceive, Release) contribute positively; sender debits (TransferSend, Commit) contribute negatively. Other transition kinds (HomeDeposit, HomeWithdrawal, escrow ops, migrate, finalize, acknowledgement) are excluded because they either require onchain backing the chain didn't enforce at this closure or belong to a different ledger.
Used to compute the ChallengeRescue amount when a challenged channel is closed: onchain payout reflects the closure version, anything strictly above didn't enforce, and the net amount the user is still owed by the node is the receives minus the sends in that interval. Signed (Open-time) and unsigned (during-challenge) rows both contribute — both are real value the state-advancer validated at submit time. The caller clamps the result at zero before issuing the rescue.
No epoch filter: a channel's in-channel rows live at a single epoch; detached post-Finalize rows have home_channel_id NULL and are already excluded by the channel_id predicate.
func (*DBStore) UpdateAppSession ¶
func (s *DBStore) UpdateAppSession(session app.AppSessionV1) error
UpdateAppSession updates existing session data with optimistic locking.
func (*DBStore) UpdateChannel ¶
UpdateChannel persists changes to a channel's metadata (status, version, etc).
func (*DBStore) UpdateStateSigsIfMissing ¶
func (s *DBStore) UpdateStateSigsIfMissing(channelID string, version uint64, userSig, nodeSig string) error
UpdateStateSigsIfMissing backfills the user and/or node signatures for a stored state when the corresponding column is currently NULL. Used by the on-chain event reactor to repair the local record once a state has been enforced on chain. Either signature may be empty, in which case that side is skipped. The IS NULL guard keeps the call idempotent on event replay and prevents overwriting a signature already populated by the user-facing RPC path.
func (*DBStore) UpdateUserStaked ¶
func (s *DBStore) UpdateUserStaked(wallet string, blockchainID uint64, amount decimal.Decimal) error
UpdateUserStaked upserts the staked amount for a user on a specific blockchain.
func (*DBStore) ValidateChannelSessionKeyForAsset ¶
func (s *DBStore) ValidateChannelSessionKeyForAsset(wallet, sessionKey, asset, metadataHash string) (bool, error)
ValidateChannelSessionKeyForAsset checks in a single query that: - a session key state exists for the (wallet, sessionKey) pair, - it is the latest version, - it is not expired, - the asset is in the allowed list, - the metadata hash matches.
type DatabaseConfig ¶
type DatabaseConfig struct {
URL string `env:"NITRONODE_DATABASE_URL" env-default:""`
Name string `env:"NITRONODE_DATABASE_NAME" env-default:""`
Schema string `env:"NITRONODE_DATABASE_SCHEMA" env-default:""`
Driver string `env:"NITRONODE_DATABASE_DRIVER" env-default:"postgres"`
Username string `env:"NITRONODE_DATABASE_USERNAME" env-default:"postgres"`
Password string `env:"NITRONODE_DATABASE_PASSWORD" env-default:"your-super-secret-and-long-postgres-password"`
Host string `env:"NITRONODE_DATABASE_HOST" env-default:"localhost"`
Port string `env:"NITRONODE_DATABASE_PORT" env-default:"5432"`
SSLMode string `env:"NITRONODE_DATABASE_SSLMODE" env-default:"require"`
Retries int `env:"NITRONODE_DATABASE_RETRIES" env-default:"5"`
// Connection pool settings
MaxOpenConns int `env:"NITRONODE_DATABASE_MAX_OPEN_CONNS" env-default:"100"`
MaxIdleConns int `env:"NITRONODE_DATABASE_MAX_IDLE_CONNS" env-default:"25"`
ConnMaxLifetime int `env:"NITRONODE_DATABASE_CONN_MAX_LIFETIME_SEC" env-default:"300"`
ConnMaxIdleTime int `env:"NITRONODE_DATABASE_CONN_MAX_IDLE_TIME_SEC" env-default:"60"`
}
In order to connect to Postgresql you need to fill out all the fields.
To connect to sqlite, you just need to specify "sqlite" driver. By default it will use in-memory database. You can provide NITRONODE_DATABASE_NAME to use the file.
For Postgresql, NITRONODE_DATABASE_URL takes precedence: when set, it is used verbatim and the individual Username/Password/Host/Port/Name/SSLMode fields are ignored.
type DatabaseStore ¶
type DatabaseStore interface {
// ExecuteInTransaction runs the provided handler within a database transaction.
// If the handler returns an error, the transaction is rolled back.
// If the handler completes successfully, the transaction is committed.
ExecuteInTransaction(handler StoreTxHandler) error
// GetUserBalances retrieves the balances for a user's wallet.
GetUserBalances(wallet string) ([]core.BalanceEntry, error)
// LockUserState locks a user's balance row for update (postgres only, must be used within a transaction).
// Uses INSERT ... ON CONFLICT DO NOTHING to ensure the row exists, then SELECT ... FOR UPDATE to lock it.
// Returns the current balance or zero if the row was just inserted.
LockUserState(wallet, asset string) (decimal.Decimal, error)
// GetUserTransactions retrieves transaction history for a user with optional filters.
GetUserTransactions(wallet string, asset *string, txType *core.TransactionType, fromTime *uint64, toTime *uint64, paginate *core.PaginationParams) ([]core.Transaction, core.PaginationMetadata, error)
// RecordTransaction creates a transaction record linking state transitions.
// applicationID is the self-declared origin tag of the client that caused
// the transaction (see rpc.ApplicationIDQueryParam); empty string means no
// app_id was supplied and the column is persisted as NULL.
RecordTransaction(tx core.Transaction, applicationID string) error
// CreateChannel creates a new channel entity in the database.
CreateChannel(channel core.Channel) error
// GetChannelByID retrieves a channel by its unique identifier.
GetChannelByID(channelID string) (*core.Channel, error)
// GetActiveHomeChannel retrieves the active home channel for a user's wallet and asset.
// "Active" includes both Void (DB-only) and Open (materialized onchain).
GetActiveHomeChannel(wallet, asset string) (*core.Channel, error)
// GetNotClosedHomeChannel retrieves the home channel for a user's wallet and asset
// regardless of status, as long as it has not reached ChannelStatusClosed. Intended
// for read paths (e.g. GetHomeChannel RPC) that must remain functional after an
// off-chain Finalize flips the channel to Closing.
GetNotClosedHomeChannel(wallet, asset string) (*core.Channel, error)
// CheckActiveChannel verifies if a user has an active home channel for the given asset
// and returns its approved signature validators and current status. A nil status means
// no active channel exists. "Active" includes Void (DB-only, awaiting onchain confirmation)
// and Open (materialized onchain); callers needing onchain materialization must additionally
// require Status == core.ChannelStatusOpen.
CheckActiveChannel(wallet, asset string) (string, *core.ChannelStatus, error)
// HasNonClosedHomeChannel returns true if any home channel for (wallet, asset) exists
// with a status other than Closed, indicating an in-progress channel lifecycle.
HasNonClosedHomeChannel(wallet, asset string) (bool, error)
// UpdateChannel persists changes to a channel's metadata (status, version, etc).
UpdateChannel(channel core.Channel) error
// GetUserChannels retrieves all channels for a user with optional status, asset, and type filters.
GetUserChannels(wallet string, status *core.ChannelStatus, asset *string, channelType *core.ChannelType, limit, offset uint32) ([]core.Channel, uint32, error)
// GetLastStateByChannelID retrieves the most recent state for a given channel.
// If signed is true, only returns states with both user and node signatures.
GetLastStateByChannelID(channelID string, signed bool) (*core.State, error)
// GetStateByChannelIDAndVersion retrieves a specific state version for a channel.
// Returns nil if the state with the specified version does not exist.
GetStateByChannelIDAndVersion(channelID string, version uint64) (*core.State, error)
// GetLastUserState retrieves the most recent state for a user's asset.
GetLastUserState(wallet, asset string, signed bool) (*core.State, error)
// StoreUserState persists a new user state to the database.
// applicationID is the self-declared origin tag of the client that caused
// the transition (see rpc.ApplicationIDQueryParam); empty string means no
// app_id was supplied and the column is persisted as NULL.
StoreUserState(state core.State, applicationID string) error
// EnsureNoOngoingStateTransitions validates that no conflicting blockchain operations are pending.
EnsureNoOngoingStateTransitions(wallet, asset string) error
// EnsureNoOngoingEscrowOperation validates that the user has no in-flight escrow
// operation (escrow_lock, mutual_lock, or unfinalized escrow_deposit/escrow_withdraw)
// that would prevent issuing a receiver-side state.
EnsureNoOngoingEscrowOperation(wallet, asset string) error
// UpdateStateSigsIfMissing backfills the user and/or node signatures for a stored
// state when the corresponding column is currently NULL. Either signature may be
// empty to skip that side.
UpdateStateSigsIfMissing(channelID string, version uint64, userSig, nodeSig string) error
// HasSignedFinalize reports whether a node-signed Finalize state exists for the given
// home channel. Used by event handlers to detect the post-Finalize lifecycle when the
// channel status field has been temporarily overwritten by an on-chain challenge.
HasSignedFinalize(channelID string) (bool, error)
// SumNetTransitionAmountAfterVersion returns the net effect on the user's
// home-channel balance of transitions stored against channelID strictly above
// minVersion. Receiver credits (TransferReceive, Release) contribute positively;
// sender debits (TransferSend, Commit) contribute negatively. Other transition
// kinds are excluded. Used to compute the ChallengeRescue amount when a
// challenged channel is closed.
SumNetTransitionAmountAfterVersion(channelID string, minVersion uint64) (decimal.Decimal, error)
// ScheduleInitiateEscrowWithdrawal queues a blockchain action to initiate withdrawal.
// This queues the state to be submitted on-chain to initiate an escrow withdrawal.
ScheduleInitiateEscrowWithdrawal(stateID string, chainID uint64) error
// ScheduleCheckpoint schedules a checkpoint operation for a home channel state.
// This queues the state to be submitted on-chain to update the channel's on-chain state.
ScheduleCheckpoint(stateID string, chainID uint64) error
// ScheduleChallenge schedules a challengeChannel(...) submission on the channel's home
// blockchain using the provided state and a node-produced challenger signature.
ScheduleChallenge(stateID string, chainID uint64) error
// ScheduleFinalizeEscrowDeposit schedules a checkpoint for an escrow deposit operation.
// This queues the state to be submitted on-chain to finalize an escrow deposit.
ScheduleFinalizeEscrowDeposit(stateID string, chainID uint64) error
// ScheduleFinalizeEscrowWithdrawal schedules a checkpoint for an escrow withdrawal operation.
// This queues the state to be submitted on-chain to finalize an escrow withdrawal.
ScheduleFinalizeEscrowWithdrawal(stateID string, chainID uint64) error
// ScheduleInitiateEscrowDeposit schedules a checkpoint for an escrow deposit operation.
// This queues the state to be submitted on-chain for an escrow deposit on home chain.
ScheduleInitiateEscrowDeposit(stateID string, chainID uint64) error
// Fail marks a blockchain action as failed and increments the retry counter.
Fail(actionID int64, err string) error
// FailNoRetry marks a blockchain action as failed without incrementing the retry counter.
FailNoRetry(actionID int64, err string) error
// RecordAttempt records a failed attempt for a blockchain action and increments the retry counter.
// The action remains in pending status.
RecordAttempt(actionID int64, err string) error
// Complete marks a blockchain action as completed with the given transaction hash.
Complete(actionID int64, txHash string) error
// GetActions retrieves pending blockchain actions, optionally limited by count.
GetActions(limit uint8, chainID uint64) ([]BlockchainAction, error)
// GetStateByID retrieves a state by its deterministic ID.
GetStateByID(stateID string) (*core.State, error)
// CreateApp registers a new application. Returns an error if the app ID already exists.
CreateApp(entry app.AppV1) error
// GetApp retrieves a single application by ID. Returns nil if not found.
GetApp(appID string) (*app.AppInfoV1, error)
// GetApps retrieves applications with optional filtering by app ID, owner wallet, and pagination.
GetApps(appID *string, ownerWallet *string, pagination *core.PaginationParams) ([]app.AppInfoV1, core.PaginationMetadata, error)
// GetAppCount returns the total number of applications owned by a specific wallet.
GetAppCount(ownerWallet string) (uint64, error)
// CreateAppSession initializes a new application session.
CreateAppSession(session app.AppSessionV1) error
// GetAppSession retrieves a specific session by ID.
GetAppSession(sessionID string) (*app.AppSessionV1, error)
// GetAppSessions retrieves filtered sessions with pagination.
GetAppSessions(appSessionID *string, participant *string, status app.AppSessionStatus, pagination *core.PaginationParams) ([]app.AppSessionV1, core.PaginationMetadata, error)
// UpdateAppSession updates existing session data.
UpdateAppSession(session app.AppSessionV1) error
// GetAppSessionBalances retrieves the total balances associated with a session.
GetAppSessionBalances(sessionID string) (map[string]decimal.Decimal, error)
// GetParticipantAllocations retrieves specific asset allocations per participant.
GetParticipantAllocations(sessionID string) (map[string]map[string]decimal.Decimal, error)
// RecordLedgerEntry logs a movement of funds within the internal ledger.
RecordLedgerEntry(userWallet, accountID, asset string, amount decimal.Decimal) error
// LockSessionKeyState seeds the pointer row for (user, session_key, kind) if absent and
// locks the (session_key, kind) row for the surrounding transaction. Returns the latest
// stored version for the caller's row and the latestExpiresAt of that version (zero time
// when the latest version is 0, i.e. no history row exists yet). Returns
// ErrSessionKeyNotAllowed if the key is bound to a different wallet for this kind.
// The latestExpiresAt return lets submit handlers distinguish a reactivation
// (prev inactive → submitted active) from a rotation (prev already active) so the
// per-user cap can be re-checked when a revoked slot is brought back.
LockSessionKeyState(userAddress, sessionKey string, kind SessionKeyKind) (latestVersion uint64, latestExpiresAt time.Time, err error)
// CountSessionKeysForUser returns the number of distinct session keys recorded for the
// wallet across both kinds. Used to enforce the per-user cap at submit time.
CountSessionKeysForUser(userAddress string) (uint32, error)
// StoreAppSessionKeyState stores or updates a session key state.
StoreAppSessionKeyState(state app.AppSessionKeyStateV1) error
GetAppSessionKeyOwner(sessionKey, appSessionId, applicationId string) (string, error)
// SessionKeyStateExists returns the latest version of a non-expired session key state for a user.
// Returns 0 if no state exists.
GetLastAppSessionKeyVersion(wallet, sessionKey string) (uint64, error)
// GetLatestSessionKeyState retrieves the latest version of a specific session key for a user.
// Returns nil if no state exists.
GetLastAppSessionKeyState(wallet, sessionKey string) (*app.AppSessionKeyStateV1, error)
// GetLastAppSessionKeyStates retrieves the latest session key states for a user with optional
// filtering. When includeInactive is false, only states whose expires_at is in the future are
// returned; when true, all latest states are returned regardless of expiry. Results are
// paginated; totalCount is the unpaginated total matching the filter.
GetLastAppSessionKeyStates(wallet string, sessionKey *string, includeInactive bool, limit, offset uint32) ([]app.AppSessionKeyStateV1, uint32, error)
// StoreChannelSessionKeyState stores or updates a channel session key state.
StoreChannelSessionKeyState(state core.ChannelSessionKeyStateV1) error
// GetLastChannelSessionKeyVersion returns the latest version for a (wallet, sessionKey) pair.
// Returns 0 if no state exists.
GetLastChannelSessionKeyVersion(wallet, sessionKey string) (uint64, error)
// GetLastChannelSessionKeyStates retrieves the latest channel session key states for a user,
// optionally filtered by session key. When includeInactive is false, only states whose
// expires_at is in the future are returned; when true, all latest states are returned
// regardless of expiry. Results are paginated; totalCount is the unpaginated total matching
// the filter.
GetLastChannelSessionKeyStates(wallet string, sessionKey *string, includeInactive bool, limit, offset uint32) ([]core.ChannelSessionKeyStateV1, uint32, error)
// ValidateChannelSessionKeyForAsset checks that a valid, non-expired session key state
// exists at its latest version for the (wallet, sessionKey) pair, includes the given asset,
// and matches the metadata hash.
ValidateChannelSessionKeyForAsset(wallet, sessionKey, asset, metadataHash string) (bool, error)
// CountActiveUsers returns distinct user counts per asset within the given window.
CountActiveUsers(window time.Duration) ([]ActiveCountByLabel, error)
// CountActiveAppSessions returns app session counts per application within the given window.
CountActiveAppSessions(window time.Duration) ([]ActiveCountByLabel, error)
// GetLifetimeMetricLastTimestamp returns the most recent last_timestamp among all metrics with the given name.
GetLifetimeMetricLastTimestamp(name string) (time.Time, error)
// GetAppSessionsCountByLabels computes app session count deltas, upserts as lifespan metrics, and returns updated totals.
GetAppSessionsCountByLabels() ([]AppSessionCount, error)
// GetChannelsCountByLabels computes channel count deltas, upserts as lifespan metrics, and returns updated totals.
GetChannelsCountByLabels() ([]ChannelCount, error)
// GetTotalValueLocked computes TVL deltas by domain (channels, app_sessions) and asset, upserts as lifespan metrics, and returns updated totals.
GetTotalValueLocked() ([]TotalValueLocked, error)
// SetNodeBalance upserts the on-chain liquidity for a given blockchain and asset.
SetNodeBalance(blockchainID uint64, asset string, value decimal.Decimal) error
// RefreshUserEnforcedBalance recomputes the locked balance from the user's open home channel on-chain state.
RefreshUserEnforcedBalance(wallet, asset string) error
// GetNodeBalance returns the on-chain liquidity per blockchain and asset.
GetNodeBalance() ([]NodeBalance, error)
// GetUserBalanceSummary returns the off-chain liquidity requirement per blockchain and asset.
GetUserBalanceSummary() ([]UserBalanceSummary, error)
// UpdateUserStaked upserts the staked amount for a user on a specific blockchain.
UpdateUserStaked(wallet string, blockchainID uint64, amount decimal.Decimal) error
// GetTotalUserStaked returns the total staked amount for a user across all blockchains.
GetTotalUserStaked(wallet string) (decimal.Decimal, error)
// RecordAction inserts a new action log entry for a user.
RecordAction(wallet string, gatedAction core.GatedAction) error
// GetUserActionCount returns the number of actions matching the given wallet, method, and path
// within the specified time window.
GetUserActionCount(wallet string, gatedAction core.GatedAction, window time.Duration) (uint64, error)
// GetUserActionCounts returns a map of gated actions to their respective counts for a user within the specified time window.
GetUserActionCounts(userWallet string, window time.Duration) (map[core.GatedAction]uint64, error)
// StoreContractEvent stores a blockchain event to prevent duplicate processing.
StoreContractEvent(ev core.BlockchainEvent) error
// GetLatestContractEventBlockNumber returns the highest block number for a given contract.
GetLatestContractEventBlockNumber(contractAddress string, blockchainID uint64) (lastBlock uint64, err error)
// IsContractEventPresent checks if a specific contract event has already been stored.
IsContractEventPresent(blockchainID, blockNumber uint64, txHash string, logIndex uint32) (isPresent bool, err error)
}
DatabaseStore defines the unified persistence layer.
func NewDBStore ¶
func NewDBStore(db *gorm.DB) DatabaseStore
type LifespanMetric ¶
type LifespanMetric struct {
ID string `gorm:"column:id;primaryKey;size:66"`
Name string `gorm:"column:name;not null"`
Labels datatypes.JSON `gorm:"column:labels;type:text"`
Value decimal.Decimal `gorm:"column:value;type:varchar(78);not null"`
LastTimestamp time.Time `gorm:"column:last_timestamp;not null"`
UpdatedAt time.Time
}
func (LifespanMetric) TableName ¶
func (LifespanMetric) TableName() string
type ListOptions ¶
type NodeBalance ¶
type NodeBalance struct {
BlockchainID string `gorm:"column:blockchain_id"`
Asset string `gorm:"column:asset"`
Value decimal.Decimal `gorm:"column:value"`
LastUpdated time.Time `gorm:"column:last_updated"`
}
NodeBalance holds on-chain liquidity for a given blockchain and asset.
type QueryDurationObserver ¶
type QueryDurationObserver interface {
ObserveDBQueryDuration(queryKind string, duration time.Duration)
}
QueryDurationObserver records the time a single gorm DB operation took. Implemented by the runtime metric exporter to avoid an import cycle (the metrics package depends on pkg/{app,core,rpc}, store/database does not).
type SessionKeyKind ¶
type SessionKeyKind uint8
SessionKeyKind discriminates the two session-key flavors stored in current_session_key_states_v1. Stored as SMALLINT in the DB.
const ( SessionKeyKindChannel SessionKeyKind = 1 SessionKeyKindAppSession SessionKeyKind = 2 )
type State ¶
type State struct {
// ID is a 64-character deterministic hash
ID string `gorm:"column:id;primaryKey;size:64"`
Asset string `gorm:"column:asset;not null"`
UserWallet string `gorm:"column:user_wallet;not null"`
Epoch uint64 `gorm:"column:epoch;not null"`
Version uint64 `gorm:"column:version;not null"`
// Transition
TransitionType uint8 `gorm:"column:transition_type;not null"`
TransitionTxID string `gorm:"column:transition_tx_id;size:66;not null"`
TransitionAccountID string `gorm:"column:transition_account_id;size:66;not null"`
TransitionAmount decimal.Decimal `gorm:"column:transition_amount;type:varchar(78);not null"`
// Optional channel references
HomeChannelID *string `gorm:"column:home_channel_id"`
EscrowChannelID *string `gorm:"column:escrow_channel_id"`
// Home Channel balances and flows
// Using decimal.Decimal for int256 values and int64 for flow values
HomeUserBalance decimal.Decimal `gorm:"column:home_user_balance;type:varchar(78)"`
HomeUserNetFlow decimal.Decimal `gorm:"column:home_user_net_flow;default:0"`
HomeNodeBalance decimal.Decimal `gorm:"column:home_node_balance;type:varchar(78)"`
HomeNodeNetFlow decimal.Decimal `gorm:"column:home_node_net_flow;default:0"`
// Escrow Channel balances and flows
EscrowUserBalance decimal.Decimal `gorm:"column:escrow_user_balance;type:varchar(78)"`
EscrowUserNetFlow decimal.Decimal `gorm:"column:escrow_user_net_flow;default:0"`
EscrowNodeBalance decimal.Decimal `gorm:"column:escrow_node_balance;type:varchar(78)"`
EscrowNodeNetFlow decimal.Decimal `gorm:"column:escrow_node_net_flow;default:0"`
UserSig *string `gorm:"column:user_sig;type:text"`
NodeSig *string `gorm:"column:node_sig;type:text"`
// ApplicationID is the self-declared origin tag of the client that caused
// this state transition (see rpc.ApplicationIDQueryParam). Advisory only.
ApplicationID *string `gorm:"column:application_id;size:66;index:idx_channel_states_app_id"`
// Read-only fields populated from JOINs with channels table
HomeBlockchainID *uint64 `gorm:"->;column:home_blockchain_id"`
HomeTokenAddress *string `gorm:"->;column:home_token_address"`
EscrowBlockchainID *uint64 `gorm:"->;column:escrow_blockchain_id"`
EscrowTokenAddress *string `gorm:"->;column:escrow_token_address"`
CreatedAt time.Time
}
State represents an immutable state in the system ID is deterministic: Hash(UserWallet, Asset, CycleIndex, Version)
type StoreTxHandler ¶
type StoreTxHandler func(DatabaseStore) error
StoreTxHandler is a function that executes Store operations within a transaction.
type TotalValueLocked ¶
type TotalValueLocked struct {
Asset string `gorm:"column:asset"`
Domain string `gorm:"column:domain"`
Value decimal.Decimal `gorm:"column:value"`
LastUpdated time.Time `gorm:"column:last_updated"`
}
TotalValueLocked holds the total value locked for a given asset, along with the last update timestamp.
type Transaction ¶
type Transaction struct {
// ID is a 64-character deterministic hash
ID string `gorm:"column:id;primaryKey;size:64"`
Type core.TransactionType `gorm:"column:tx_type;not null;index:idx_type;index:idx_from_to_account"`
AssetSymbol string `gorm:"column:asset_symbol;not null"`
FromAccount string `gorm:"column:from_account;not null;index:idx_from_account;index:idx_from_to_account"`
ToAccount string `gorm:"column:to_account;not null;index:idx_to_account;index:idx_from_to_account"`
SenderNewStateID *string `gorm:"column:sender_new_state_id;size:64"`
ReceiverNewStateID *string `gorm:"column:receiver_new_state_id;size:64"`
Amount decimal.Decimal `gorm:"column:amount;type:decimal(38,18);not null"`
CreatedAt time.Time
// ApplicationID is the self-declared origin tag of the client that caused
// this transaction (see rpc.ApplicationIDQueryParam). Advisory only.
ApplicationID *string `gorm:"column:application_id;size:66;index:idx_transactions_app_id"`
}
Transaction represents an immutable transaction in the system ID is deterministic based on transaction initiation: 1) Initiated by User: Hash(ToAccount, SenderNewStateID) 2) Initiated by Node: Hash(FromAccount, ReceiverNewStateID)
func (Transaction) TableName ¶
func (Transaction) TableName() string
type UserBalance ¶
type UserBalance struct {
UserWallet string `gorm:"column:user_wallet;primaryKey;size:42"`
Asset string `gorm:"column:asset;primaryKey;size:20"`
Balance decimal.Decimal `gorm:"column:balance;type:varchar(78);not null"`
Enforced decimal.Decimal `gorm:"column:enforced;type:varchar(78);not null;default:0"`
HomeBlockchainID uint64 `gorm:"column:home_blockchain_id;not null;default:0"`
CreatedAt time.Time `gorm:"column:created_at"`
UpdatedAt time.Time `gorm:"column:updated_at"`
}
UserBalance represents aggregated user balance for an asset
func (UserBalance) TableName ¶
func (UserBalance) TableName() string
TableName specifies the table name for the UserBalance model
type UserBalanceSummary ¶
type UserBalanceSummary struct {
BlockchainID string `gorm:"column:home_blockchain_id"`
Asset string `gorm:"column:asset"`
Total decimal.Decimal `gorm:"column:total"`
Underfunded decimal.Decimal `gorm:"column:underfunded"`
Releasable decimal.Decimal `gorm:"column:releasable"`
}
UserBalanceSummary holds off-chain liquidity metrics for a given blockchain and asset. BlockchainID is kept as a string to match the Prometheus exporter's label type, avoiding conversions at the call site.
type UserStakedV1 ¶
type UserStakedV1 struct {
UserWallet string `gorm:"column:user_wallet;primaryKey;not null"`
BlockchainID uint64 `gorm:"column:blockchain_id;primaryKey;not null"`
Amount decimal.Decimal `gorm:"column:amount;type:varchar(78);not null"`
CreatedAt time.Time
UpdatedAt time.Time
}
func (UserStakedV1) TableName ¶
func (UserStakedV1) TableName() string
Source Files
¶
- action_log.go
- app.go
- app_ledger.go
- app_session.go
- app_session_key_state.go
- blockchain_action.go
- channel.go
- channel_session_key_state.go
- contract_event.go
- current_session_key_state.go
- database.go
- db_store.go
- interface.go
- lifespan_metric.go
- list_options.go
- metrics.go
- state.go
- testing.go
- transaction.go
- user_staked.go
- utils.go