The endorserdb package provides storage services for validation records in Panurus. It manages the persistence and querying of token transaction validation records that are created during the endorsement process.
The endorser database stores validation records that track token requests validated by endorsers. Each validation record contains:
- Transaction ID
- Token request data
- Validation metadata
- Public parameters hash
- Status and status message
- Timestamp
The endorserdb follows the same architectural pattern as other storage services in Panurus:
endorserdb (Service Layer)
↓
db/driver (Interface Layer)
↓
db/sql/common (SQL Implementation)
↓
db/sql/{postgres,sqlite} (Database-Specific)
-
Service Layer (
store.go):StoreService: High-level API for validation record operationsStoreServiceManager: Manages store instances per TMS IDValidationRecordsIterator: Iterator for query results
-
Driver Interface (
db/driver/endorser.go):EndorserStore: Read operations interfaceEndorserStoreTransaction: Write operations interfaceValidationRecord: Data structure for validation recordsQueryValidationRecordsParams: Query parameters
-
SQL Implementation (
db/sql/common/endorser.go):- Core SQL logic for validation record storage
- Query building and execution
- Transaction management
-
Database-Specific (
db/sql/{postgres,sqlite}/endorser.go):- Database-specific wrappers
- Condition and pagination interpreters
import "github.com/LFDT-Panurus/panurus/token/services/storage/endorserdb"
// Get store service manager
manager := endorserdb.NewStoreServiceManager(configService, drivers)
// Get store service for a specific TMS
store, err := manager.StoreServiceByTMSId(tmsID)
if err != nil {
return err
}err := store.AppendValidationRecord(
ctx,
txID,
tokenRequest,
metadata,
ppHash,
)Unlike TTXDB and AuditDB, which are handed an already-deserialised *token.Request, this store
receives raw token request bytes taken off the wire. It therefore checks them before filing them
as a validated request: txID, tokenRequest, and ppHash must all be non-empty, and
tokenRequest must deserialise at a supported protocol version and carry at least one action. A
validation record asserting that a request was validated is worthless if the request it names carries
nothing to validate.
The check is not a substitute for validation. The caller
(token/services/network/fabric/endorsement/fsc/responder.go) must still run
validator.UnmarshallAndVerifyWithMetadata and take ppHash from its own TMS rather than from
the peer that sent the request. The store's checks narrow what a skipped validation can look like;
they cannot tell whether the actions are legal. Note also that this format is the bare
actions-and-signatures encoding, which carries no anchor, so — unlike TTXDB — a record here cannot be
bound to its transaction id by a structural check. See
Store Integrity Verification.
// Query with time range
from := time.Now().Add(-24 * time.Hour)
to := time.Now()
it, err := store.ValidationRecords(ctx, endorserdb.QueryValidationRecordsParams{
From: &from,
To: &to,
})
if err != nil {
return err
}
defer it.Close()
// Iterate through results
for {
record, err := it.Next()
if err != nil {
break
}
// Process record
}err := store.SetStatus(ctx, txID, driver.Confirmed, "Transaction confirmed")status, message, err := store.GetStatus(ctx, txID)The endorserdb uses a single, self-contained table:
Stores validation records created during endorsement:
tx_id: Transaction identifier (primary key)request: Token request data (NOT NULL)metadata: Validation metadata (NOT NULL)pp_hash: Public parameters hash (NOT NULL)status: Validation status (NOT NULL)status_message: Status message (NOT NULL)stored_at: Timestamp (NOT NULL)
There is no foreign key to the Requests table — a validation record can be created and have its status tracked entirely independently of any TTXDB/AuditDB Requests row for the same tx_id.
The endorserdb was created by extracting validation-related functionality from the Token Transaction Database (ttxdb). Both services share the same physical database, but each owns its own table (ttxdb owns Requests/Transactions/Movements/Endorsements, endorserdb owns Validations) and interface:
- ttxdb: Manages token transactions, movements, and token requests
- endorserdb: Manages validation records and their status
This separation provides better modularity and clearer separation of concerns.
The endorserdb uses the same configuration as other storage services:
token:
tms:
mytms:
endorserdb:
persistence:
type: sql
opts:
driver: postgres
dataSource: "host=localhost port=5432 user=postgres password=postgres dbname=tokendb sslmode=disable"# Run endorser-specific tests
go test ./token/services/storage/db/sql/postgres -run TestEndorser
go test ./token/services/storage/db/sql/sqlite -run TestEndorser# Run endorser integration tests
make integration-tests-endorserIf you're migrating code that previously used ttxdb for validation records:
-
Replace imports:
// Old import "github.com/LFDT-Panurus/panurus/token/services/storage/ttxdb" // New import "github.com/LFDT-Panurus/panurus/token/services/storage/endorserdb"
-
Update method calls:
// Old ttxStore.AppendValidationRecord(ctx, txID, request, metadata, ppHash) ttxStore.ValidationRecords(ctx, params) // New endorserStore.AppendValidationRecord(ctx, txID, request, metadata, ppHash) endorserStore.ValidationRecords(ctx, params)
-
Update transaction creation:
// Old tx, err := ttxStore.NewTransactionStoreTransaction() tx.AddValidationRecord(...) // New tx, err := endorserStore.NewEndorserStoreTransaction() tx.AddValidationRecord(...)