Skip to content

Commit

Permalink
Store enc key CID in a block instead of height
Browse files Browse the repository at this point in the history
  • Loading branch information
islamaliev committed Aug 13, 2024
1 parent 20f574c commit dcf36e7
Show file tree
Hide file tree
Showing 16 changed files with 345 additions and 250 deletions.
26 changes: 26 additions & 0 deletions crypto/cid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2024 Democratized Data Foundation
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package crypto

import (
"github.com/ipfs/go-cid"
"github.com/multiformats/go-multihash"
)

// GenerateCid generates a CID from the given data.
func GenerateCid(data []byte) (cid.Cid, error) {
mh, err := multihash.Sum(data, multihash.SHA2_256, -1)
if err != nil {
return cid.Cid{}, err
}

return cid.NewCidV1(cid.Raw, mh), nil
}
12 changes: 6 additions & 6 deletions internal/core/block/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ const (
type Encryption struct {
// Type indicates on what level encryption is applied.
Type EncryptionType
// From specifies the block height from which the encryption is applied.
From uint64
// CID of the key used for encryption.
KeyID []byte
}

// Block is a block that contains a CRDT delta and links to other blocks.
Expand All @@ -129,7 +129,7 @@ type Block struct {

// IsEncrypted returns true if the block is encrypted.
func (b *Block) IsEncrypted() bool {
return b.Encryption != nil && (*b.Encryption).Type != NotEncrypted
return b.Encryption != nil && b.Encryption.Type != NotEncrypted
}

// GetPrevBlockCid returns the CID of the previous block.
Expand All @@ -155,7 +155,7 @@ func (b Block) IPLDSchemaBytes() []byte {
type Encryption struct {
type EncryptionType
from Int
keyID Bytes
}
type EncryptionType enum {
Expand Down Expand Up @@ -298,8 +298,8 @@ func (b *Block) Validate() error {
return ErrInvalidBlockEncryptionType
}

if (*b.Encryption).From == 0 {
return ErrInvalidBlockEncryptionFrom
if len(b.Encryption.KeyID) == 0 {
return ErrInvalidBlockEncryptionKeyID
}
}
return nil
Expand Down
14 changes: 7 additions & 7 deletions internal/core/block/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,17 +237,17 @@ func TestBlock_Validate(t *testing.T) {
}{
{
name: "NotEncrypted type is valid",
encryption: &Encryption{Type: NotEncrypted, From: 1},
encryption: &Encryption{Type: NotEncrypted, KeyID: []byte{1}},
expectedError: nil,
},
{
name: "DocumentEncrypted type is valid",
encryption: &Encryption{Type: DocumentEncrypted, From: 1},
encryption: &Encryption{Type: DocumentEncrypted, KeyID: []byte{1}},
expectedError: nil,
},
{
name: "FieldEncrypted type is valid",
encryption: &Encryption{Type: FieldEncrypted, From: 1},
encryption: &Encryption{Type: FieldEncrypted, KeyID: []byte{1}},
expectedError: nil,
},
{
Expand All @@ -257,13 +257,13 @@ func TestBlock_Validate(t *testing.T) {
},
{
name: "Invalid encryption type",
encryption: &Encryption{Type: EncryptionType(99), From: 1},
encryption: &Encryption{Type: EncryptionType(99), KeyID: []byte{1}},
expectedError: ErrInvalidBlockEncryptionType,
},
{
name: "Invalid encryption from parameter",
encryption: &Encryption{Type: DocumentEncrypted},
expectedError: ErrInvalidBlockEncryptionFrom,
name: "Invalid encryption key id parameter",
encryption: &Encryption{Type: DocumentEncrypted, KeyID: []byte{}},
expectedError: ErrInvalidBlockEncryptionKeyID,
},
}

Expand Down
24 changes: 12 additions & 12 deletions internal/core/block/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,25 @@ import (
)

const (
errNodeToBlock string = "failed to convert node to block"
errEncodingBlock string = "failed to encode block"
errUnmarshallingBlock string = "failed to unmarshal block"
errGeneratingLink string = "failed to generate link"
errInvalidBlockEncryptionType string = "invalid block encryption type"
errInvalidBlockEncryptionFrom string = "invalid block encryption from parameter"
errNodeToBlock string = "failed to convert node to block"
errEncodingBlock string = "failed to encode block"
errUnmarshallingBlock string = "failed to unmarshal block"
errGeneratingLink string = "failed to generate link"
errInvalidBlockEncryptionType string = "invalid block encryption type"
errInvalidBlockEncryptionKeyID string = "invalid block encryption key id"
)

// Errors returnable from this package.
//
// This list is incomplete and undefined errors may also be returned.
// Errors returned from this package may be tested against these errors with errors.Is.
var (
ErrNodeToBlock = errors.New(errNodeToBlock)
ErrEncodingBlock = errors.New(errEncodingBlock)
ErrUnmarshallingBlock = errors.New(errUnmarshallingBlock)
ErrGeneratingLink = errors.New(errGeneratingLink)
ErrInvalidBlockEncryptionType = errors.New(errInvalidBlockEncryptionType)
ErrInvalidBlockEncryptionFrom = errors.New(errInvalidBlockEncryptionFrom)
ErrNodeToBlock = errors.New(errNodeToBlock)
ErrEncodingBlock = errors.New(errEncodingBlock)
ErrUnmarshallingBlock = errors.New(errUnmarshallingBlock)
ErrGeneratingLink = errors.New(errGeneratingLink)
ErrInvalidBlockEncryptionType = errors.New(errInvalidBlockEncryptionType)
ErrInvalidBlockEncryptionKeyID = errors.New(errInvalidBlockEncryptionKeyID)
)

// NewErrFailedToGetPriority returns an error indicating that the priority could not be retrieved.
Expand Down
13 changes: 6 additions & 7 deletions internal/core/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -800,25 +800,24 @@ type EncStoreDocKey struct {
// FieldName is the name of the field that the key is for.
// If unset, it indicates that the key is for the whole document.
FieldName immutable.Option[string]
// BlockHeight is the height of the block that the key is for.
// It is used to differentiate keys that are used in different point in time.
BlockHeight uint64
// KeyID is a hash (Cid) of the of the encryption key.
KeyID string
}

var _ Key = (*EncStoreDocKey)(nil)

// NewEncStoreDocKey creates a new EncStoreDocKey from a docID and fieldID.
// Unset fieldName indicates that the key is for the whole document.
// blockHeight is the height of the block that the key is for.
func NewEncStoreDocKey(docID string, fieldName immutable.Option[string], blockHeight uint64) EncStoreDocKey {
return EncStoreDocKey{DocID: docID, FieldName: fieldName, BlockHeight: blockHeight}
func NewEncStoreDocKey(docID string, fieldName immutable.Option[string], keyID string) EncStoreDocKey {
return EncStoreDocKey{DocID: docID, FieldName: fieldName, KeyID: keyID}
}

func (k EncStoreDocKey) ToString() string {
if k.FieldName.HasValue() {
return fmt.Sprintf("%s/%s/%d", k.DocID, k.FieldName.Value(), k.BlockHeight)
return fmt.Sprintf("%s/%s/%s", k.DocID, k.FieldName.Value(), k.KeyID)
}
return fmt.Sprintf("%s/%d", k.DocID, k.BlockHeight)
return fmt.Sprintf("%s/%s", k.DocID, k.KeyID)
}

func (k EncStoreDocKey) Bytes() []byte {
Expand Down
33 changes: 16 additions & 17 deletions internal/db/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
package db

import (
"bytes"
"container/list"
"context"
"sync"
Expand Down Expand Up @@ -153,7 +154,7 @@ func (db *db) mergeEncryptedBlocks(ctx context.Context, keyEvent encryption.KeyR
return err
}

blocks, err = loadBlocksChainFromBlockstoreTillHeight(ctx, txn, cids, mergeGroup.compositeKey.BlockHeight)
blocks, err = loadBlocksWithKeyIDFromBlockstore(ctx, txn, cids, mergeGroup.compositeKey.KeyID)
if err != nil {
return err
}
Expand All @@ -171,7 +172,7 @@ func (db *db) mergeEncryptedBlocks(ctx context.Context, keyEvent encryption.KeyR
return err
}

fieldBlocks, err := loadBlocksChainFromBlockstoreTillHeight(ctx, txn, cids, fieldStoreKey.BlockHeight)
fieldBlocks, err := loadBlocksWithKeyIDFromBlockstore(ctx, txn, cids, fieldStoreKey.KeyID)
if err != nil {
return err
}
Expand Down Expand Up @@ -387,16 +388,16 @@ func (mp *mergeProcessor) processEncryptedBlock(
if blockEnc.Type == coreblock.FieldEncrypted {
fieldName = immutable.Some(dagBlock.Delta.GetFieldName())
}
mp.addPendingEncryptionRequest(docID, fieldName, blockEnc.From)
mp.addPendingEncryptionRequest(docID, fieldName, string(blockEnc.KeyID))
}
return dagBlock, true, nil
}
}
return dagBlock, false, nil
}

func (mp *mergeProcessor) addPendingEncryptionRequest(docID string, fieldName immutable.Option[string], height uint64) {
mp.pendingEncryptionKeyRequests[core.NewEncStoreDocKey(docID, fieldName, height)] = struct{}{}
func (mp *mergeProcessor) addPendingEncryptionRequest(docID string, fieldName immutable.Option[string], keyID string) {
mp.pendingEncryptionKeyRequests[core.NewEncStoreDocKey(docID, fieldName, keyID)] = struct{}{}
if !fieldName.HasValue() {
mp.hasPendingCompositeBlock = true
}
Expand Down Expand Up @@ -470,7 +471,7 @@ func decryptBlock(ctx context.Context, block *coreblock.Block) (*coreblock.Block
optFieldName = immutable.Some(block.Delta.GetFieldName())
}

encStoreKey := core.NewEncStoreDocKey(string(block.Delta.GetDocID()), optFieldName, blockEnc.From)
encStoreKey := core.NewEncStoreDocKey(string(block.Delta.GetDocID()), optFieldName, string(blockEnc.KeyID))

if block.Delta.IsComposite() {
// for composite blocks there is nothing to decrypt
Expand Down Expand Up @@ -609,14 +610,14 @@ func loadBlockFromBlockStore(ctx context.Context, txn datastore.Txn, cid cid.Cid
return block, nil
}

// loadBlocksChainFromBlockstoreTillHeight loads the blocks from the blockstore starting from the given CIDs
// until it reaches a block with a height equal to the given height (including that block).
// The returned blocks are ordered from the highest height to the lowest.
func loadBlocksChainFromBlockstoreTillHeight(
// loadBlocksWithKeyIDFromBlockstore loads the blocks from the blockstore that have given encryption
// keyID until it reaches a block with a different keyID or without any.
// The returned blocks are ordered from the newest to the oldest.
func loadBlocksWithKeyIDFromBlockstore(
ctx context.Context,
txn datastore.Txn,
cids []cid.Cid,
height uint64,
keyID string,
) ([]*coreblock.Block, error) {
var blocks []*coreblock.Block
for len(cids) > 0 {
Expand All @@ -626,13 +627,11 @@ func loadBlocksChainFromBlockstoreTillHeight(
return nil, err
}

if block.Delta.GetPriority() >= height {
if block.Encryption != nil && bytes.Equal(block.Encryption.KeyID, []byte(keyID)) {
blocks = append(blocks, block)
if block.Delta.GetPriority() != height {
prevCid := block.GetPrevBlockCid()
if prevCid.HasValue() {
cids = append(cids, prevCid.Value())
}
prevCid := block.GetPrevBlockCid()
if prevCid.HasValue() {
cids = append(cids, prevCid.Value())
}
}
cids = cids[1:]
Expand Down
Loading

0 comments on commit dcf36e7

Please sign in to comment.