Skip to content

Commit

Permalink
This commit addresses #698
Browse files Browse the repository at this point in the history
Signed-off-by: Angelo De Caro <[email protected]>
  • Loading branch information
adecaro committed Dec 3, 2024
1 parent 7b0b14e commit ae34132
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 57 deletions.
4 changes: 4 additions & 0 deletions platform/common/core/generic/vault/inspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ func (i *Inspector) SetState(driver.Namespace, driver.PKey, driver.RawValue) err
panic("programming error: the rwset inspector is read-only")
}

func (i *Inspector) AddReadAt(ns driver.Namespace, key string, version Version) error {
panic("programming error: the rwset inspector is read-only")
}

func (i *Inspector) GetState(namespace driver.Namespace, key driver.PKey, _ ...driver.GetStateOpt) (driver.RawValue, error) {
return i.Rws.WriteSet.Get(namespace, key), nil
}
Expand Down
5 changes: 5 additions & 0 deletions platform/common/core/generic/vault/interceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ func (i *Interceptor[V]) Clear(ns string) error {
return nil
}

func (i *Interceptor[V]) AddReadAt(ns driver.Namespace, key string, version Version) error {
i.Rws.ReadSet.Add(ns, key, version)
return nil
}

func (i *Interceptor[V]) GetReadKeyAt(ns string, pos int) (string, error) {
if i.IsClosed() {
return "", errors.New("this instance was closed")
Expand Down
80 changes: 27 additions & 53 deletions platform/common/core/generic/vault/interceptor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,76 +10,40 @@ import (
"sync"
"testing"

"github.com/hyperledger-labs/fabric-smart-client/platform/common/core/generic/vault/mocks"
"github.com/hyperledger-labs/fabric-smart-client/platform/common/driver"
"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections"
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/assert"
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/flogging"
"github.com/stretchr/testify/assert"
)

func newMockQE() mockQE {
return mockQE{
State: VersionedValue{
Raw: []byte("raw"),
Version: blockTxIndexToBytes(1, 1),
},
Metadata: map[string][]byte{
"md": []byte("meta"),
},
}
}

type mockQE struct {
State VersionedValue
Metadata map[string][]byte
}

func (qe mockQE) GetStateMetadata(driver.Namespace, driver.PKey) (driver.Metadata, driver.RawVersion, error) {
return qe.Metadata, blockTxIndexToBytes(1, 1), nil
}
func (qe mockQE) GetState(driver.Namespace, driver.PKey) (VersionedValue, error) {
return qe.State, nil
}
func (qe mockQE) Done() {
}

type mockTXIDStoreReader struct {
}

func (m mockTXIDStoreReader) Iterator(interface{}) (collections.Iterator[*driver.ByNum[int]], error) {
panic("not implemented")
}
func (m mockTXIDStoreReader) Get(txID driver.TxID) (int, string, error) {
return 1, txID, nil
}

func TestConcurrency(t *testing.T) {
qe := newMockQE()
idsr := mockTXIDStoreReader{}
qe := mocks.MockQE{}
idsr := mocks.MockTXIDStoreReader{}

i := newInterceptor(flogging.MustGetLogger("interceptor_test"), qe, idsr, "1")
s, err := i.GetState("ns", "key")
assert.NoError(err)
assert.Equal(qe.State.Raw, s, "with no opts, getstate should return the FromStorage value (query executor)")
assert.NoError(t, err)
assert.Equal(t, qe.State.Raw, s, "with no opts, getstate should return the FromStorage value (query executor)")

md, err := i.GetStateMetadata("ns", "key")
assert.NoError(err)
assert.Equal(qe.Metadata, md, "with no opts, GetStateMetadata should return the FromStorage value (query executor)")
assert.NoError(t, err)
assert.Equal(t, qe.Metadata, md, "with no opts, GetStateMetadata should return the FromStorage value (query executor)")

s, err = i.GetState("ns", "key", driver.FromBoth)
assert.NoError(err)
assert.Equal(qe.State.Raw, s, "FromBoth should fallback to FromStorage with empty rwset")
assert.NoError(t, err)
assert.Equal(t, qe.State.Raw, s, "FromBoth should fallback to FromStorage with empty rwset")

md, err = i.GetStateMetadata("ns", "key", driver.FromBoth)
assert.NoError(err)
assert.Equal(qe.Metadata, md, "FromBoth should fallback to FromStorage with empty rwset")
assert.NoError(t, err)
assert.Equal(t, qe.Metadata, md, "FromBoth should fallback to FromStorage with empty rwset")

s, err = i.GetState("ns", "key", driver.FromIntermediate)
assert.NoError(err)
assert.Equal([]byte(nil), s, "FromIntermediate should return empty result from empty rwset")
assert.NoError(t, err)
assert.Equal(t, []byte(nil), s, "FromIntermediate should return empty result from empty rwset")

md, err = i.GetStateMetadata("ns", "key", driver.FromIntermediate)
assert.NoError(err)
assert.True(md == nil, "FromIntermediate should return empty result from empty rwset")
assert.NoError(t, err)
assert.True(t, md == nil, "FromIntermediate should return empty result from empty rwset")

// Done in parallel
wg := sync.WaitGroup{}
Expand All @@ -94,5 +58,15 @@ func TestConcurrency(t *testing.T) {
wg.Wait()

_, err = i.GetState("ns", "key")
assert.Error(err, "this instance was closed")
assert.Error(t, err, "this instance was closed")
}

func TestAddReadAt(t *testing.T) {
qe := mocks.MockQE{}
idsr := mocks.MockTXIDStoreReader{}
i := newInterceptor(flogging.MustGetLogger("interceptor_test"), qe, idsr, "1")

assert.NoError(t, i.AddReadAt("ns", "key", []byte("version")))
assert.Len(t, i.RWs().Reads, 1)
assert.Equal(t, []byte("version"), i.RWs().Reads["ns"]["key"])
}
47 changes: 47 additions & 0 deletions platform/common/core/generic/vault/mocks/mocks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package mocks

import (
"encoding/binary"

"github.com/hyperledger-labs/fabric-smart-client/platform/common/driver"
"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections"
)

type MockQE struct {
State driver.VersionedValue
Metadata map[string][]byte
}

func (qe MockQE) GetStateMetadata(driver.Namespace, driver.PKey) (driver.Metadata, driver.RawVersion, error) {
return qe.Metadata, blockTxIndexToBytes(1, 1), nil
}

func (qe MockQE) GetState(driver.Namespace, driver.PKey) (driver.VersionedValue, error) {
return qe.State, nil
}

func (qe MockQE) Done() {
}

type MockTXIDStoreReader struct {
}

func (m MockTXIDStoreReader) Iterator(interface{}) (collections.Iterator[*driver.ByNum[int]], error) {
panic("not implemented")
}
func (m MockTXIDStoreReader) Get(txID driver.TxID) (int, string, error) {
return 1, txID, nil
}

func blockTxIndexToBytes(Block driver.BlockNum, TxNum driver.TxNum) []byte {
buf := make([]byte, 8)
binary.BigEndian.PutUint32(buf[:4], uint32(Block))
binary.BigEndian.PutUint32(buf[4:], uint32(TxNum))
return buf
}
8 changes: 4 additions & 4 deletions platform/common/core/generic/vault/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ type BlockTxIndexVersionBuilder struct{}
func (b *BlockTxIndexVersionBuilder) VersionedValues(rws *ReadWriteSet, ns driver2.Namespace, writes NamespaceWrites, block driver2.BlockNum, indexInBloc driver2.TxNum) (map[driver2.PKey]VersionedValue, error) {
vals := make(map[driver2.PKey]driver.VersionedValue, len(writes))
for pkey, val := range writes {
vals[pkey] = driver.VersionedValue{Raw: val, Version: blockTxIndexToBytes(block, indexInBloc)}
vals[pkey] = driver.VersionedValue{Raw: val, Version: BlockTxIndexToBytes(block, indexInBloc)}
}
return vals, nil
}

func (b *BlockTxIndexVersionBuilder) VersionedMetaValues(rws *ReadWriteSet, ns driver2.Namespace, writes KeyedMetaWrites, block driver2.BlockNum, indexInBloc driver2.TxNum) (map[driver2.PKey]driver2.VersionedMetadataValue, error) {
vals := make(map[driver2.PKey]driver2.VersionedMetadataValue, len(writes))
for pkey, val := range writes {
vals[pkey] = driver2.VersionedMetadataValue{Metadata: val, Version: blockTxIndexToBytes(block, indexInBloc)}
vals[pkey] = driver2.VersionedMetadataValue{Metadata: val, Version: BlockTxIndexToBytes(block, indexInBloc)}
}
return vals, nil
}
Expand All @@ -57,10 +57,10 @@ func (m BlockTxIndexVersionMarshaller) FromBytes(data Version) (driver2.BlockNum
}

func (m BlockTxIndexVersionMarshaller) ToBytes(bn driver2.BlockNum, txn driver2.TxNum) Version {
return blockTxIndexToBytes(bn, txn)
return BlockTxIndexToBytes(bn, txn)
}

func blockTxIndexToBytes(Block driver2.BlockNum, TxNum driver2.TxNum) []byte {
func BlockTxIndexToBytes(Block driver2.BlockNum, TxNum driver2.TxNum) []byte {
buf := make([]byte, 8)
binary.BigEndian.PutUint32(buf[:4], uint32(Block))
binary.BigEndian.PutUint32(buf[4:], uint32(TxNum))
Expand Down
3 changes: 3 additions & 0 deletions platform/common/driver/rwset.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ type RWSet interface {
// Clear remove the passed namespace from this rwset
Clear(ns Namespace) error

// AddReadAt adds a read dependency for the given namespace and key at the given version
AddReadAt(ns Namespace, key string, version RawVersion) error

// SetState sets the given value for the given namespace and key.
SetState(namespace Namespace, key PKey, value RawValue) error

Expand Down

0 comments on commit ae34132

Please sign in to comment.