Documentation
¶
Overview ¶
Package object wires the S3 OBJECT path to the S-Chain storage VM, proving the on-chain-metadata / off-chain-blob split end to end:
- On PUT, the blob bytes are streamed to a VOLUME server (a needle write) — OFF chain. The volume returns a file id (fid) per blob. The blob NEVER enters a block.
- The small MANIFEST {bucket, object, fileIds, size, etag} is submitted as a PutManifest tx to the S-Chain VM — ON chain. Only this consensus-sized metadata becomes block state.
- On GET, the manifest is read back from the VM (GetManifest), the fids it names are streamed from the volume, and the original blob is reconstructed.
The Volume interface below is the SEAM. For M1 it is satisfied by a faithful in-memory stub (memvolume.go) whose Write/Read mirror the hanzo/s3 volume contract: Write(blob) -> fid, Read(fid) -> blob. For M2, the real hanzo/s3 volume client (github.com/hanzoai/s3 s3/operation.SubmitFiles, which assigns a volume + streams the needle and returns SubmitResult.Fid) plugs in HERE, behind this identical interface — see the M2 PLUG POINT note on Volume. Keeping the seam in chains/schain (rather than importing the hanzoai/s3 module into the luxfi/chains module) respects the org/module boundary while proving the exact data model the real client will satisfy.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrBlobNotFound is returned by Volume.Read when no blob is stored under fid. ErrBlobNotFound = errors.New("object: blob not found in volume") // ErrEmptyBlob rejects a PutObject with no bytes (M1 stores at least one fid). ErrEmptyBlob = errors.New("object: empty blob") )
Functions ¶
This section is empty.
Types ¶
type Chain ¶
type Chain interface {
// PutManifest submits a PutManifest{bucket,object,fileIds,size,etag} tx and
// drives it to Accept, returning only after the manifest is committed.
PutManifest(ctx context.Context, bucket, object string, m Manifest) error
// GetManifest returns the committed manifest for (bucket, object).
GetManifest(bucket, object string) (Manifest, bool, error)
}
Chain is the S-Chain VM surface the object path drives. It is the consensus seam: PutManifest submits the metadata tx and SEALS it through a block (the caller-supplied sealer plays the consensus engine's build->verify->accept), and GetManifest reads committed manifest state back. *schain.ChainVM satisfies this via a thin adapter (see the chains/schain object_roundtrip_test.go harness), keeping object/ free of an import cycle on package schain.
type Manifest ¶
Manifest is the on-chain metadata for one object: the file ids of its blobs (off chain), the total size, and the content etag. It mirrors the schain state.Manifest / txs.PutManifestTx fields — the consensus-sized record that is the ONLY thing the object path commits to a block.
type MemVolume ¶
type MemVolume struct {
// contains filtered or unexported fields
}
MemVolume is a faithful in-memory stand-in for the hanzo/s3 volume server, used to prove the object round-trip for M1 without a running volume daemon. It honours the Volume contract exactly: Write assigns a fresh file id in the SeaweedFS "volumeId,needleIdCookie" form the real volume returns, stores the bytes under it (the needle), and Read returns those bytes verbatim. It is the OFF-CHAIN store — nothing here ever touches a block.
M2 swaps this for the real volume client; the VM and object.go are unaffected because both sides speak only the Volume interface.
func NewMemVolume ¶
func NewMemVolume() *MemVolume
NewMemVolume returns an empty in-memory volume bound to a single logical volumeId (a real deployment shards across many; one suffices for the M1 proof).
func (*MemVolume) Has ¶
Has reports whether fid is present — used by tests to assert the blob lives in the volume (off chain) and not in any block.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the S3 object path: it splits each object into an OFF-CHAIN blob (to the Volume) and an ON-CHAIN manifest (to the Chain). It owns neither — it is the thin orchestrator that proves the split.
func New ¶
New builds an object Store over a volume (off-chain blobs) and a chain (on-chain manifests).
func (*Store) GetObject ¶
func (s *Store) GetObject(ctx context.Context, bucket, object string) (blob []byte, m Manifest, found bool, err error)
GetObject is the S3 GET path:
- read the manifest from the chain (ON chain) — the fids + size + etag.
- stream each fid's blob from the volume (OFF chain) and concatenate them back into the original object bytes.
found is false when no manifest exists for (bucket, object).
func (*Store) PutObject ¶
func (s *Store) PutObject(ctx context.Context, bucket, object string, blob []byte) (Manifest, error)
PutObject is the S3 PUT path:
- stream the blob to the volume (OFF chain) -> fid; the blob NEVER enters a block.
- submit PutManifest{bucket, object, [fid], size, etag} to the chain (ON chain) and drive it to Accept.
It returns the committed manifest. ETag is the S3-canonical base64(md5(blob)), matching the form hanzo/s3's volume upload returns (ContentMd5), so the on-chain etag is identical whether the blob went through the stub or the real volume.
type Volume ¶
type Volume interface {
// Write streams blob to the volume (OFF chain) and returns its file id.
Write(blob []byte) (fid string, err error)
// Read streams the blob bytes for fid back from the volume. Returns
// ErrBlobNotFound if no such blob exists.
Read(fid string) (blob []byte, err error)
}
Volume is the OFF-CHAIN blob store seam. It is the minimal projection of the hanzo/s3 volume server the object path needs: write bytes, get a file id back; read a file id, get the bytes back. The fid is opaque to this package — it is the volume's own address (the SeaweedFS-style "volumeId,needleIdCookie" string the real s3 volume returns).
M2 PLUG POINT: replace the in-memory stub (NewMemVolume) with a thin adapter over github.com/hanzoai/s3 s3/operation.SubmitFiles:
Write(blob) -> SubmitFiles(...).Fid (assign volume + stream needle) Read(fid) -> GET http://<volume>/<fid> (stream needle bytes back)
No code in object.go / the VM changes — only this interface's implementation.