Skip to content

Commit

Permalink
feat: configurable seal version for test committer/confirmer (#32)
Browse files Browse the repository at this point in the history
AB#10098

Co-authored-by: Robin Bryce <[email protected]>
  • Loading branch information
robinbryce and Robin Bryce authored Nov 4, 2024
1 parent 4b33c6e commit 4d53d75
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 26 deletions.
4 changes: 4 additions & 0 deletions massifs/massifcontextverified.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ func (mc *MassifContext) verifyContextV1(
// before replicating the new data.
if options.trustedBaseState != nil {

if options.trustedBaseState.Version == int(MMRStateVersion0) {
return nil, fmt.Errorf("unsupported MMR state version 0 (you should promote to v1 on demand using mmr.PeakHashes)")
}

ok, _, err = mmr.CheckConsistency(
mc, sha256.New(),
options.trustedBaseState.MMRSize,
Expand Down
2 changes: 1 addition & 1 deletion massifs/massifpeakstack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ func TestPeakStack_Height4Massif2to3Size63(t *testing.T) {
iBaseLeafNode45 := iPeakNode45 - mmr.IndexHeight(iPeakNode45)
iLeaf45 := mmr.LeafCount(iBaseLeafNode45)

hsz := mmr.HeightSize(uint64(committer.cfg.MassifHeight))
hsz := mmr.HeightSize(uint64(committer.Cfg.MassifHeight))
hlc := (hsz + 1) / 2
mi30 := iLeaf30 / hlc
mcPeakNode30, err := massifReader.GetMassif(ctx, tenantIdentity, mi30)
Expand Down
35 changes: 23 additions & 12 deletions massifs/testcommitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ type TestCommitterConfig struct {
CommitmentEpoch uint32
MassifHeight uint8
SealOnCommit bool
SealerKey *ecdsa.PrivateKey
UseV0Seals bool
}
type TestMinimalCommitter struct {
cfg TestCommitterConfig
Cfg TestCommitterConfig
log logger.Logger
g mmrtesting.TestGenerator
tc mmrtesting.TestContext
Expand All @@ -36,7 +38,6 @@ type TestMinimalCommitter struct {
SealIssuer string
RootSigner RootSigner
CoseSigner *azkeys.TestCoseSigner
SealerKey *ecdsa.PrivateKey
SealerPubKey *ecdsa.PublicKey
}

Expand All @@ -51,22 +52,24 @@ func NewTestMinimalCommitter(

log := logger.Sugar.WithServiceName("merklebuilderv1")
c := TestMinimalCommitter{
cfg: cfg,
Cfg: cfg,
log: logger.Sugar.WithServiceName("TestCommitter"),
tc: tc,
g: g,
committer: *NewMassifCommitter(
MassifCommitterConfig{CommitmentEpoch: cfg.CommitmentEpoch}, log, tc.GetStorer()),
leafGenerator: leafGenerator,
}
if !c.cfg.SealOnCommit {
if !c.Cfg.SealOnCommit {
return c, nil
}

c.SealIssuer = "seal.datatrails.ai"
key := TestGenerateECKey(tc.T, elliptic.P256())
c.SealerKey = &key
c.CoseSigner = azkeys.NewTestCoseSigner(tc.T, key)
if c.Cfg.SealerKey == nil {
key := TestGenerateECKey(tc.T, elliptic.P256())
c.Cfg.SealerKey = &key
}
c.CoseSigner = azkeys.NewTestCoseSigner(tc.T, *c.Cfg.SealerKey)
codec, err := NewRootSignerCodec()
require.NoError(tc.T, err)
c.RootSigner = NewRootSigner(c.SealIssuer, codec)
Expand All @@ -75,12 +78,12 @@ func NewTestMinimalCommitter(

func (c *TestMinimalCommitter) GetCurrentContext(
ctx context.Context, tenantIdentity string, massifHeight uint8) (MassifContext, error) {
return c.committer.GetCurrentContext(ctx, tenantIdentity, c.cfg.MassifHeight)
return c.committer.GetCurrentContext(ctx, tenantIdentity, c.Cfg.MassifHeight)
}

// ContextCommitted seals the current massif context if the context is configure with SealOnCommit
func (c *TestMinimalCommitter) ContextCommitted(ctx context.Context, tenantIdentity string, mc MassifContext) error {
if !c.cfg.SealOnCommit {
if !c.Cfg.SealOnCommit {
return nil
}

Expand All @@ -98,10 +101,18 @@ func (c *TestMinimalCommitter) ContextCommitted(ctx context.Context, tenantIdent
MMRSize: mmrSize,
Peaks: peaks,
Timestamp: time.Now().UnixMilli(),
CommitmentEpoch: c.cfg.CommitmentEpoch,
CommitmentEpoch: c.Cfg.CommitmentEpoch,
IDTimestamp: mc.GetLastIdTimestamp(),
}

if c.Cfg.UseV0Seals {
// downgrade the seal to v0
state.LegacySealRoot = mmr.HashPeaksRHS(sha256.New(), peaks)
state.Peaks = nil
state.Version = int(MMRStateVersion0)
// everything else is the same
}

subject := TenantMassifBlobPath(tenantIdentity, uint64(mc.Start.MassifIndex))
publicKey, err := c.CoseSigner.PublicKey()
if err != nil {
Expand Down Expand Up @@ -137,7 +148,7 @@ func (c *TestMinimalCommitter) AddLeaves(
if count == 0 {
return nil
}
mc, err := c.committer.GetCurrentContext(ctx, tenantIdentity, c.cfg.MassifHeight)
mc, err := c.committer.GetCurrentContext(ctx, tenantIdentity, c.Cfg.MassifHeight)
if err != nil {
c.log.Infof("AddLeaves: %v", err)
return err
Expand All @@ -162,7 +173,7 @@ func (c *TestMinimalCommitter) AddLeaves(
if err != nil {
return err
}
mc, err = c.committer.GetCurrentContext(ctx, tenantIdentity, c.cfg.MassifHeight)
mc, err = c.committer.GetCurrentContext(ctx, tenantIdentity, c.Cfg.MassifHeight)
if err != nil {
c.log.Infof("AddLeaves: %v", err)
return err
Expand Down
65 changes: 53 additions & 12 deletions massifs/testlocalreadercontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package massifs

import (
"context"
"crypto/ecdsa"
"strings"
"testing"

Expand All @@ -18,45 +19,62 @@ type TestLocalReaderContext struct {
AzuriteContext mmrtesting.TestContext
TestConfig mmrtesting.TestConfig
CommitterConfig TestCommitterConfig
LogOptions TestLogOptions

G mmrtesting.TestGenerator
// We use a regular massif reader attached to azurite to test the local massif reader.
AzuriteReader MassifReader
}

// TestLogCreatorContext holds the context data resulting from a call to CreateLog
// TestLogOptions holds the context data resulting from a call to CreateLog
// Unless one or more of the TEstCreateLogOptions are used, the context will not have anything interesting in it.
type TestLogCreatorContext struct {
Preimages map[uint64][]byte
type TestLogOptions struct {
Preimages map[uint64][]byte
ContinueExisting bool // if true, don'
SealKey *ecdsa.PrivateKey
UsingV0Seals bool
}

type TestCreateLogOption func(*TestLogCreatorContext)
type TestLogOption func(*TestLogOptions)

func TestWithCreateLogPreImages() TestCreateLogOption {
return func(c *TestLogCreatorContext) {
func TestWithCreateLogPreImages() TestLogOption {
return func(c *TestLogOptions) {
c.Preimages = make(map[uint64][]byte)
}
}

func TestWithSealKey(key *ecdsa.PrivateKey) TestLogOption {
return func(c *TestLogOptions) {
c.SealKey = key
}
}

func TestWithV0Seals() TestLogOption {
return func(c *TestLogOptions) {
c.UsingV0Seals = true
}
}

// CreateLog creates a log with the given tenant identity, massif height, and mmr size,
// any previous seal or massif blobs for the same tenant are first deleted
// To create a single incomplete massif, call AddLeavesToLog with a leafCount instead of CreateLog
func (c *TestLocalReaderContext) CreateLog(
tenantIdentity string, massifHeight uint8, massifCount uint32,
opts ...TestCreateLogOption) {
opts ...TestLogOption) {

logContext := &TestLogCreatorContext{}
options := &TestLogOptions{}
for _, opt := range opts {
opt(logContext)
opt(options)
}

generator := MMRTestingGenerateNumberedLeaf

// If the caller needs to work with the pre-images we wrap the generator to retain them
if logContext.Preimages != nil {
if options.Preimages != nil {
generator = func(tenantIdentity string, base, i uint64) mmrtesting.AddLeafArgs {

args := generator(tenantIdentity, base, i)
logContext.Preimages[base+i] = args.Value
options.Preimages[base+i] = args.Value
return args
}
}
Expand All @@ -68,24 +86,47 @@ func (c *TestLocalReaderContext) CreateLog(
CommitmentEpoch: 1,
MassifHeight: massifHeight,
SealOnCommit: true, // create seals for each massif as we go
SealerKey: options.SealKey,
UseV0Seals: options.UsingV0Seals,
}, c.AzuriteContext, c.G, generator)
require.NoError(c.AzuriteContext.T, err)

leavesPerMassif := mmr.HeightIndexLeafCount(uint64(massifHeight) - 1)

// using base = 0 means the caller can't predict the leaf hash based on the mmr index, but otherwise it's fine
// if the caller is overriding the generator, they can do what they like
err = committer.AddLeaves(context.TODO(), tenantIdentity, 0, leavesPerMassif*uint64(massifCount))
require.NoError(c.AzuriteContext.T, err)
}

// AddLeavesToLog adds the requested number of leaves to the log for the given
// tenant identity. Note the massifHeight must be the same as was provided to
// the corresponding CreateLog call
func (c *TestLocalReaderContext) AddLeavesToLog(tenantIdentity string, massifHeight uint8, leafCount int) {
// To create a single incomplete massif, call AddLeavesToLog with a leafCount instead of CreateLog
func (c *TestLocalReaderContext) AddLeavesToLog(tenantIdentity string, massifHeight uint8, leafCount int, opts ...TestLogOption) {

options := &TestLogOptions{}
for _, opt := range opts {
opt(options)
}
generator := MMRTestingGenerateNumberedLeaf

// If the caller needs to work with the pre-images we wrap the generator to retain them
if options.Preimages != nil {
generator = func(tenantIdentity string, base, i uint64) mmrtesting.AddLeafArgs {

args := generator(tenantIdentity, base, i)
options.Preimages[base+i] = args.Value
return args
}
}

committer, err := NewTestMinimalCommitter(TestCommitterConfig{
CommitmentEpoch: 1,
MassifHeight: massifHeight,
SealOnCommit: true, // create seals for each massif as we go
SealerKey: options.SealKey,
UseV0Seals: options.UsingV0Seals,
}, c.AzuriteContext, c.G, MMRTestingGenerateNumberedLeaf)
require.NoError(c.AzuriteContext.T, err)

Expand Down
2 changes: 1 addition & 1 deletion tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ replace (

require (
github.com/datatrails/go-datatrails-common v0.18.0
github.com/datatrails/go-datatrails-merklelog/massifs v0.0.0-00010101000000-000000000000
github.com/datatrails/go-datatrails-merklelog/massifs v0.2.1
github.com/datatrails/go-datatrails-merklelog/mmr v0.1.1
github.com/stretchr/testify v1.9.0
)
Expand Down

0 comments on commit 4d53d75

Please sign in to comment.