User Wallet Data Synchronization
Ty Everett ([email protected])
Abstract
This specification defines an interoperable synchronization protocol for user wallet data between wallet storage providers. It standardizes the chunked, resumable sync model implemented by Wallet Toolbox so independent storage backends can exchange wallet state without proprietary adapters.
The protocol is incremental. A consumer requests successive sync chunks for a specific wallet identity using a since watermark and per-entity offsets. The producer returns updated records in dependency order. The consumer merges those records, maintains a remote-to-local ID mapping, and advances the sync state until all entity arrays are present and empty.
Motivation
Wallets increasingly need to replicate user state across multiple storage backends:
local and remote storage
active and backup providers
device migration and recovery flows
managed wallet infrastructure built from interchangeable components
Without a standard sync protocol, each wallet implementation must define its own export/import format and state-reconciliation logic. That prevents interoperability even when both systems already implement the same wallet behaviors.
This specification addresses that problem by defining the synchronization behavior already used in Wallet Toolbox, including:
resumable incremental replication
per-entity pagination
identity-safe replication scoped to one wallet user
convergent merging through persistent ID mapping
Specification
Scope
This specification applies to synchronization between wallet storage providers for a single wallet user.
It does not define:
wallet-to-application APIs such as BRC-100
backup file formats
encryption of exported wallet data at rest or in transit
This specification is transport-agnostic. Any transport may be used provided it can faithfully convey the request and response structures defined below.
Terminology
Producer: The storage provider supplying wallet records.
Consumer: The storage provider receiving and merging wallet records.
Sync cycle: A sequence of one or more chunk requests sharing the same
sincevalue until the producer reports completion.Sync state: Consumer-maintained state for a specific remote storage provider and wallet identity.
Entity offset: The number of records for a given entity type already received within the current sync cycle.
ID map: A mapping from producer-local numeric IDs to consumer-local numeric IDs.
Record Model
Wallet data is synchronized as typed entity records. This specification defines the following entity names:
provenTxoutputBasketoutputTagtxLabeltransactionoutputtxLabelMapoutputTagMapcertificatecertificateFieldcommissionprovenTxReq
In addition, a producer may return a single user record describing the synchronized user.
Each synchronized entity record:
MUST belong to the wallet user identified by the request
identityKeyMUST include
created_atandupdated_atMUST NOT contain
nullvalues; omitted fields MUST be omitted rather than sent asnull
When serialized through JSON, timestamps SHOULD use RFC 3339 / ISO 8601 date-time strings.
Sync State
The consumer MUST maintain a sync state for each pair:
wallet user identity
remote producer storage identity
The sync state MUST include:
producer
storageIdentityKeyproducer
storageNamecurrent
sincewatermark, if anyper-entity
countoffsets for the current sync cycleper-entity
maxUpdated_atobserved during the current sync cycleper-entity
idMap
The consumer MUST treat the sync state as durable. If synchronization is interrupted, the next attempt MUST resume from the stored since and offsets.
Request Structure
The consumer requests a chunk using the following structure:
Request Rules
fromStorageIdentityKeyMUST identify the producer.toStorageIdentityKeyMUST identify the consumer.identityKeyMUST identify the wallet user whose records are being synchronized.sinceMUST be omitted for an initial full sync.maxItemsMUST bound the total number of records returned across all entity arrays.maxRoughSizeMUST bound the approximate serialized size of the returned chunk.offsetsMUST be supplied in the exact entity order defined in this specification.
If an offsets entry is missing, duplicated, or out of order, the producer MUST reject the request.
Producer Behavior
For a given request, the producer MUST build the response as follows:
Initialize the response with
fromStorageIdentityKey,toStorageIdentityKey, anduserIdentityKey.If
sinceis absent, or if the user recordupdated_atis later thansince, include theuserrecord.Process entity types in the exact order defined in this specification.
For each entity type, return records for the requested user whose
updated_atis greater than or equal tosince.Skip the first
offsetmatching records for that entity type.Continue adding records until either:
no more records remain for that entity type, or
maxItemsis exhausted, ormaxRoughSizeis exceeded
The producer MUST include the record that causes maxRoughSize to be exceeded, then stop adding further records.
If the producer begins processing an entity type in the response, it MUST include that entity property in the chunk, even if the resulting array is empty.
If the producer stops before reaching a later entity type because of size or count limits, the unattempted later entity properties MUST be omitted from the chunk.
The producer MUST use a deterministic record order that remains stable throughout a sync cycle so the consumer can safely resume by offset.
Response Structure
The producer returns a SyncChunk:
Each entity array is interpreted as follows:
undefined/ omitted: the producer did not attempt that entity type in this chunk[]: the producer attempted that entity type and found no further matching records at the currentsinceand offsetnon-empty array: records to be merged
Completion Condition
A sync cycle is complete only when all entity-array properties are present and each of them is empty.
The presence or absence of the optional user record does not by itself determine completion.
Inclusive since Semantics
since SemanticsThe producer MUST treat since as an inclusive lower bound:
a record matches when
updated_at >= since
This means a resumed sync cycle will typically repeat at least one previously seen record. Consumers MUST therefore merge records idempotently and MUST NOT treat repeated records as an error.
Consumer Merge Behavior
For each returned entity record, the consumer MUST:
determine whether the producer record matches an existing local record under that entity's convergent equality rules
update the existing local record if necessary, or insert a new local record if no match exists
update the entity's
idMapso the producer-local primary ID maps to the consumer-local primary IDupdate the entity's
maxUpdated_atwith the greatestupdated_atvalue observed for that entity during the current sync cycleincrease the entity
countby the number of records received for that entity in the chunk
The consumer MUST preserve idMap consistency. If an existing producer ID maps to a different local ID than previously recorded, synchronization MUST fail.
For entity types whose identity is relationship-based rather than primary-ID-based, an implementation MAY omit idMap usage. Wallet Toolbox does this for:
certificateFieldtxLabelMapoutputTagMap
Advancing Sync State
If the current chunk does not complete the sync cycle:
the consumer MUST retain the current
sincethe consumer MUST retain the updated per-entity
countoffsetsthe consumer MUST request the next chunk using those updated offsets
If the current chunk completes the sync cycle:
the consumer MUST set
sinceto the maximumupdated_atobserved during the cycle, if anythe consumer MUST reset every entity
countoffset to0the consumer MUST begin the next cycle from the new
since
If a completed cycle produced no merged records and no new maximum timestamp, the consumer MAY leave since unchanged.
Authentication and Authorization
A producer MUST only return data for the authenticated wallet identity associated with identityKey.
A producer MUST reject requests that attempt to synchronize another user's records.
This specification does not mandate a specific authentication protocol, but an implementation MUST ensure:
the caller is authorized to read the requested user's wallet data
fromStorageIdentityKeyandtoStorageIdentityKeyare not forgeable within the synchronization context
Error Handling
Synchronization MUST fail if:
the requested
identityKeyis unknown or unauthorizedthe
offsetslist is malformed or out of dependency orderrequired timestamps are missing or invalid
any returned entity contains
nullvaluesthe consumer detects a conflicting
idMapassignment
On failure, the consumer MUST preserve enough sync state to either retry safely or report the last durable state to the operator.
Interoperability Notes
This specification intentionally follows the chunked sync model implemented by Wallet Toolbox:
getSyncChunkon the producer sideprocessSyncChunkon the consumer sidedurable per-remote
syncStatepersistent
syncMapfor remote-to-local ID reconciliation
Implementations that follow this specification can plug into Toolbox-style sync flows interoperably without reverse-engineering private behavior.
Implementation
Wallet Toolbox implements this synchronization model across its storage providers and storage manager.
An implementation is considered conformant if it:
produces request and response objects compatible with this specification
honors inclusive
sincesemantics and resumable offsetsmerges records convergently and durably maintains sync state
References
Last updated
Was this helpful?

