diff options
| author | Linus Nordberg <linus@nordberg.se> | 2022-05-24 23:33:38 +0200 | 
|---|---|---|
| committer | Linus Nordberg <linus@nordberg.se> | 2022-05-24 23:33:38 +0200 | 
| commit | c003c2fc189748f082c09a2b4a729eb1c5732668 (patch) | |
| tree | 4430d208e1233a4345b79cd4bd094210ab69a02a /pkg/state | |
| parent | be80db7ce938e5cd8876b9b371c206dbd359b1eb (diff) | |
wip
Diffstat (limited to 'pkg/state')
| -rw-r--r-- | pkg/state/single.go | 60 | ||||
| -rw-r--r-- | pkg/state/single_sec.go | 108 | 
2 files changed, 164 insertions, 4 deletions
| diff --git a/pkg/state/single.go b/pkg/state/single.go index 695f0e3..2e44fee 100644 --- a/pkg/state/single.go +++ b/pkg/state/single.go @@ -8,18 +8,21 @@ import (  	"sync"  	"time" +	"git.sigsum.org/log-go/pkg/client"  	"git.sigsum.org/log-go/pkg/db"  	"git.sigsum.org/sigsum-go/pkg/log" +	//"git.sigsum.org/sigsum-go/pkg/requests"  	"git.sigsum.org/sigsum-go/pkg/types"  ) -// StateManagerSingle implements a single-instance StateManager +// StateManagerSingle implements a single-instance StateManager for primary nodes  type StateManagerSingle struct {  	client    db.Client  	signer    crypto.Signer  	namespace types.Hash  	interval  time.Duration  	deadline  time.Duration +	secondary *client.Client  	// Lock-protected access to pointers.  A write lock is only obtained once  	// per interval when doing pointer rotation.  All endpoints are readers. @@ -32,13 +35,14 @@ type StateManagerSingle struct {  	cosignatures map[types.Hash]*types.Signature  } -func NewStateManagerSingle(client db.Client, signer crypto.Signer, interval, deadline time.Duration) (*StateManagerSingle, error) { +func NewStateManagerSingle(dbcli db.Client, signer crypto.Signer, interval, deadline time.Duration, securl string, secpk types.PublicKey) (*StateManagerSingle, error) {  	sm := &StateManagerSingle{ -		client:    client, +		client:    dbcli,  		signer:    signer,  		namespace: *types.HashFn(signer.Public().(ed25519.PublicKey)),  		interval:  interval,  		deadline:  deadline, +		secondary: client.NewClient(securl, secpk),  	}  	sth, err := sm.latestSTH(context.Background())  	sm.setCosignedTreeHead() @@ -157,9 +161,57 @@ func (sm *StateManagerSingle) latestSTH(ctx context.Context) (*types.SignedTreeH  	if err != nil {  		return nil, fmt.Errorf("failed fetching tree head: %v", err)  	} -	sth, err := th.Sign(sm.signer, &sm.namespace) + +	//pth, err := choseTree(ctx, sm.deadline, sm.secondary, th) +	pth, err := th, nil	// DEBUG +	if err != nil { +		return nil, fmt.Errorf("failed chosing tree head: %v", err) +	} + +	sth, err := pth.Sign(sm.signer, &sm.namespace)  	if err != nil {  		return nil, fmt.Errorf("failed signing tree head: %v", err)  	} +  	return sth, nil  } + +func choseTree(ctx context.Context, deadline time.Duration, secondary *client.Client, th *types.TreeHead) (*types.TreeHead, error) { +	// TODO: handle multiple secondaries and not just one + +	if !secondary.Configured { +		return th, nil +	} + +	sctx, cancel := context.WithTimeout(ctx, deadline) // FIXME: use a separate timeout value for secondaries? +	defer cancel() +	secsth, err := secondary.GetCurrentTreeHead(sctx) +	if err != nil { +		return nil, fmt.Errorf("failed getting the latest tree head from all secondaries: %v", err) +	} + +	if secsth.TreeSize < th.TreeSize { +		// We're stuck at secsth.size so let's verify +		// consistency since secsth and sign that + +		// TODO: get and verify consinstency proof + +		// req := &requests.ConsistencyProof{ +		// 	OldSize: secsth.TreeSize, +		// 	NewSize: th.TreeSize, +		// } + +		// proof, err := sm.client.GetConsistencyProof(ctx, req) +		// if err != nil { +		// 	return nil, fmt.Errorf("unable to get consistency proof from %d to %d: %v", req.OldSize, req.NewSize, err) +		// } + +		// if !proof.Verify() { +		// 	return nil, fmt.Errorf("invalid consistency proof from %d to %d", req.OldSize, req.NewSize) +		// } + +		th = &secsth.TreeHead // FIXME: need to copy? +	} + +	return th, nil +} diff --git a/pkg/state/single_sec.go b/pkg/state/single_sec.go new file mode 100644 index 0000000..9c69fa8 --- /dev/null +++ b/pkg/state/single_sec.go @@ -0,0 +1,108 @@ +package state + +import ( +	"context" +	"crypto" +	"crypto/ed25519" +	"fmt" +	"sync" +	"time" + +	"git.sigsum.org/log-go/pkg/client" +	"git.sigsum.org/log-go/pkg/db" +	"git.sigsum.org/sigsum-go/pkg/log" +	//"git.sigsum.org/sigsum-go/pkg/requests" +	"git.sigsum.org/sigsum-go/pkg/types" +) + +// StateManagerSingleSecondary implements a single-instance StateManager for secondary nodes +type StateManagerSingleSecondary struct { +	client    db.Client +	signer    crypto.Signer +	namespace types.Hash +	interval  time.Duration +	deadline  time.Duration +	primary   *client.Client + +	// Lock-protected access to pointers.  A write lock is only obtained once +	// per interval when doing pointer rotation.  All endpoints are readers. +	sync.RWMutex +	signedTreeHead *types.SignedTreeHead +} + +func NewStateManagerSingleSecondary(dbcli db.Client, signer crypto.Signer, interval, deadline time.Duration, primurl string, primpk types.PublicKey) (*StateManagerSingleSecondary, error) { +	sm := &StateManagerSingleSecondary{ +		client:    dbcli, +		signer:    signer, +		namespace: *types.HashFn(signer.Public().(ed25519.PublicKey)), +		interval:  interval, +		deadline:  deadline, +		primary:   client.NewClient(primurl, primpk), +	} +	sth, err := sm.latestSTH(context.Background()) +	sm.setSignedTreeHead(sth) +	return sm, err +} + +func (sm *StateManagerSingleSecondary) Run(ctx context.Context) { +	rotation := func() { +		nextSTH, err := sm.latestSTH(ctx) +		if err != nil { +			log.Warning("cannot rotate without tree head: %v", err) +			return +		} +		sm.rotate(nextSTH) +	} + +	ticker := time.NewTicker(sm.interval) +	defer ticker.Stop() + +	// TODO: fetch leaves from primary + +	rotation() +	for { +		select { +		case <-ticker.C: +			rotation() +		case <-ctx.Done(): +			return +		} +	} +} + +func (sm *StateManagerSingleSecondary) AddCosignature(ctx context.Context, pub *types.PublicKey, sig *types.Signature) error { +	return fmt.Errorf("internal error: AddCosignature() called in secondary node") +} +func (sm *StateManagerSingleSecondary) CosignedTreeHead(_ context.Context) (*types.CosignedTreeHead, error) { +	return nil, fmt.Errorf("internal error: AddCosignature() called in secondary node") +} +func (sm *StateManagerSingleSecondary) ToCosignTreeHead(_ context.Context) (*types.SignedTreeHead, error) { +	return nil, fmt.Errorf("internal error: AddCosignature() called in secondary node") +} + +func (sm *StateManagerSingleSecondary) setSignedTreeHead(nextSTH *types.SignedTreeHead) { +	sm.signedTreeHead = nextSTH +} + +func (sm *StateManagerSingleSecondary) latestSTH(ctx context.Context) (*types.SignedTreeHead, error) { +	ictx, cancel := context.WithTimeout(ctx, sm.deadline) +	defer cancel() + +	th, err := sm.client.GetTreeHead(ictx) +	if err != nil { +		return nil, fmt.Errorf("failed fetching tree head: %v", err) +	} +	sth, err := th.Sign(sm.signer, &sm.namespace) +	if err != nil { +		return nil, fmt.Errorf("failed signing tree head: %v", err) +	} +	return sth, nil +} + +func (sm *StateManagerSingleSecondary) rotate(nextSTH *types.SignedTreeHead) { +	sm.Lock() +	defer sm.Unlock() + +	log.Debug("rotating tree heads") +	sm.setSignedTreeHead(nextSTH) +} | 
