diff --git a/massifs/mmriver.go b/massifs/mmriver.go index f868594..4f85544 100644 --- a/massifs/mmriver.go +++ b/massifs/mmriver.go @@ -128,66 +128,38 @@ func VerifySignedInclusionReceipt( return true, root, nil } -type ReceiptBuilder struct { - log logger.Logger - massifReader MassifReader - cborCodec commoncbor.CBORCodec - sealReader SignedRootReader - - massifHeight uint8 +type verifiedContextGetter interface { + GetVerifiedContext( + ctx context.Context, tenantIdentity string, massifIndex uint64, + opts ...ReaderOption, + ) (*VerifiedContext, error) } -// newReceiptBuilder creates a new receiptBuilder configured with all the necessary readers and information required to build a receipt -// Note that errors are logged assuming the calling context is retrieving a receipt, -// and that all returned errors are StatusErrors that can be returned to the client or nil -func NewReceiptBuilder(log logger.Logger, reader azblob.Reader, massifHeight uint8) (ReceiptBuilder, error) { - - var err error - - b := ReceiptBuilder{ - log: log, - massifHeight: massifHeight, - } - - b.massifReader = NewMassifReader(log, reader) - if b.cborCodec, err = NewRootSignerCodec(); err != nil { - return ReceiptBuilder{}, err - } - b.sealReader = NewSignedRootReader(log, reader, b.cborCodec) - b.massifHeight = massifHeight - - return b, nil -} - -func (b *ReceiptBuilder) BuildReceipt( - ctx context.Context, tenantIdentity string, mmrIndex uint64, +// GetReceipt returns a COSE receipt for the given tenantIdentity and mmrIndex +func NewReceipt( + ctx context.Context, + massifHeight uint8, + tenantIdentity string, mmrIndex uint64, + getter verifiedContextGetter, ) (*commoncose.CoseSign1Message, error) { - log := b.log.FromContext(ctx) + log := logger.Sugar.FromContext(ctx) defer log.Close() + massifIndex := uint32(MassifIndexFromMMRIndex(massifHeight, mmrIndex)) - massifIndex := MassifIndexFromMMRIndex(b.massifHeight, mmrIndex) - - // Get the seal with the latest peak for this event - massif, err := b.massifReader.GetMassif(ctx, tenantIdentity, massifIndex) + verified, err := getter.GetVerifiedContext(ctx, tenantIdentity, uint64(massifIndex)) if err != nil { return nil, fmt.Errorf( - "%w: failed to read massif %d for %s", err, massifIndex, tenantIdentity) + "%w: failed to get verified context %d for %s", err, massifIndex, tenantIdentity) } - sealContext := LogBlobContext{ - BlobPath: TenantMassifSignedRootPath(tenantIdentity, uint32(massifIndex)), - } + msg, state := verified.Sign1Message, verified.MMRState - msg, state, err := b.sealReader.ReadLogicalContext(ctx, sealContext) - if err != nil { - return nil, fmt.Errorf("failed to read seal: %s, %v", sealContext.BlobPath, err) - } - - proof, err := mmr.InclusionProof(&massif, state.MMRSize-1, mmrIndex) + proof, err := mmr.InclusionProof(&verified.MassifContext, state.MMRSize-1, mmrIndex) if err != nil { return nil, fmt.Errorf( - "failed to generating inclusion proof: %d in MMR(%d), %v", mmrIndex, state.MMRSize, err) + "failed to generating inclusion proof: %d in MMR(%d), %v", + mmrIndex, verified.MMRState.MMRSize, err) } peakIndex := mmr.PeakIndex(mmr.LeafCount(state.MMRSize), len(proof)) @@ -232,3 +204,43 @@ func (b *ReceiptBuilder) BuildReceipt( return signed, nil } + +type ReceiptBuilder struct { + log logger.Logger + massifReader MassifReader + cborCodec commoncbor.CBORCodec + massifHeight uint8 +} + +// newReceiptBuilder creates a new receiptBuilder configured with all the necessary readers and information required to build a receipt +// Note that errors are logged assuming the calling context is retrieving a receipt, +// and that all returned errors are StatusErrors that can be returned to the client or nil +func NewReceiptBuilder(log logger.Logger, reader azblob.Reader, massifHeight uint8) (ReceiptBuilder, error) { + + var err error + + b := ReceiptBuilder{ + log: log, + massifHeight: massifHeight, + } + + if b.cborCodec, err = NewRootSignerCodec(); err != nil { + return ReceiptBuilder{}, err + } + b.massifHeight = massifHeight + b.massifReader = NewMassifReader(log, reader) + sealReader := NewSignedRootReader(log, reader, b.cborCodec) + b.massifReader = NewMassifReader(log, reader, WithSealGetter(&sealReader)) + + return b, nil +} + +func (b *ReceiptBuilder) BuildReceipt( + ctx context.Context, tenantIdentity string, mmrIndex uint64, +) (*commoncose.CoseSign1Message, error) { + + log := b.log.FromContext(ctx) + defer log.Close() + + return NewReceipt(ctx, b.massifHeight, tenantIdentity, mmrIndex, &b.massifReader) +} diff --git a/massifs/rootsigner.go b/massifs/rootsigner.go index 72cdcea..3e90b37 100644 --- a/massifs/rootsigner.go +++ b/massifs/rootsigner.go @@ -47,7 +47,7 @@ const ( type MMRState struct { // Version is present in all seals from version 1. The initial release was implicity version 0. - Version int `cbor:"7,keyasint"` + Version int `cbor:"7,keyasint,omitempty"` // The size of the mmr defines the path to the root (and the full structure // of the tree). Note that all subsequent mmr states whose size is *greater* @@ -55,11 +55,11 @@ type MMRState struct { // hence can be used to verify 'old' receipts. This property is due to the // strict append only structure of the tree. MMRSize uint64 `cbor:"1,keyasint"` - LegacySealRoot []byte `cbor:"2,keyasint"` // Valid in Version 0 only. + LegacySealRoot []byte `cbor:"2,keyasint,omitempty"` // Valid in Version 0 only // The peak hashes for the mmr identified by MMRSize, this is also the packed accumulator for the tree state. // All inclusion proofs for any node under MMRSize will lead directly to one // of these peaks, or can be extended to do so. - Peaks [][]byte `cbor:"8,keyasint"` // Version 1+ + Peaks [][]byte `cbor:"8,keyasint,omitempty"` // Version 1+ // Timestamp is the unix time (milliseconds) read at the time the root was // signed. Including it allows for the same root to be re-signed. Timestamp int64 `cbor:"3,keyasint"`