aboutsummaryrefslogtreecommitdiff
path: root/pkg/state/state_manager.go
diff options
context:
space:
mode:
authorRasmus Dahlberg <rasmus@mullvad.net>2021-12-20 19:53:54 +0100
committerRasmus Dahlberg <rasmus@mullvad.net>2021-12-20 19:53:54 +0100
commitdda238b9fc105219f220f0ec3b341b0c81b71301 (patch)
treeedbbb787ccd1c1816edfa44caf749c8be68b7bf9 /pkg/state/state_manager.go
parent5ba4a77233549819440cc41a02503f3a85213e24 (diff)
types: Start using sigsum-lib-go
This commit does not change the way in which the log behaves externally. In other words, all changes are internal and involves renaming and code restructuring. Most notably picking up the refactored sigsum-lib-go.
Diffstat (limited to 'pkg/state/state_manager.go')
-rw-r--r--pkg/state/state_manager.go148
1 files changed, 3 insertions, 145 deletions
diff --git a/pkg/state/state_manager.go b/pkg/state/state_manager.go
index 84431be..5aa7609 100644
--- a/pkg/state/state_manager.go
+++ b/pkg/state/state_manager.go
@@ -2,157 +2,15 @@ package state
import (
"context"
- "crypto"
- "crypto/ed25519"
- "fmt"
- "reflect"
- "sync"
- "time"
- "github.com/golang/glog"
- "github.com/google/certificate-transparency-go/schedule"
- "git.sigsum.org/sigsum-log-go/pkg/trillian"
- "git.sigsum.org/sigsum-log-go/pkg/types"
+ "git.sigsum.org/sigsum-lib-go/pkg/types"
)
-// StateManager coordinates access to the log's tree heads and (co)signatures
+// StateManager coordinates access to a log's tree heads and (co)signatures
type StateManager interface {
Latest(context.Context) (*types.SignedTreeHead, error)
ToSign(context.Context) (*types.SignedTreeHead, error)
Cosigned(context.Context) (*types.CosignedTreeHead, error)
- AddCosignature(context.Context, *[types.VerificationKeySize]byte, *[types.SignatureSize]byte) error
+ AddCosignature(context.Context, *types.PublicKey, *types.Signature) error
Run(context.Context)
}
-
-// StateManagerSingle implements the StateManager interface. It is assumed that
-// the log server is running on a single-instance machine. So, no coordination.
-type StateManagerSingle struct {
- client trillian.Client
- signer crypto.Signer
- interval time.Duration
- deadline time.Duration
- sync.RWMutex
-
- // cosigned is the current cosigned tree head that is being served
- cosigned types.CosignedTreeHead
-
- // tosign is the current tree head that is being cosigned by witnesses
- tosign types.SignedTreeHead
-
- // cosignature keeps track of all cosignatures for the tosign tree head
- cosignature map[[types.HashSize]byte]*types.SigIdent
-}
-
-func NewStateManagerSingle(client trillian.Client, signer crypto.Signer, interval, deadline time.Duration) (*StateManagerSingle, error) {
- sm := &StateManagerSingle{
- client: client,
- signer: signer,
- interval: interval,
- deadline: deadline,
- }
-
- ctx, _ := context.WithTimeout(context.Background(), sm.deadline)
- sth, err := sm.Latest(ctx)
- if err != nil {
- return nil, fmt.Errorf("Latest: %v", err)
- }
-
- sm.cosigned = types.CosignedTreeHead{
- SignedTreeHead: *sth,
- SigIdent: []*types.SigIdent{},
- }
- sm.tosign = *sth
- sm.cosignature = map[[types.HashSize]byte]*types.SigIdent{}
- return sm, nil
-}
-
-func (sm *StateManagerSingle) Run(ctx context.Context) {
- schedule.Every(ctx, sm.interval, func(ctx context.Context) {
- ictx, _ := context.WithTimeout(ctx, sm.deadline)
- nextSTH, err := sm.Latest(ictx)
- if err != nil {
- glog.Warningf("rotate failed: Latest: %v", err)
- return
- }
-
- sm.Lock()
- defer sm.Unlock()
- sm.rotate(nextSTH)
- })
-}
-
-func (sm *StateManagerSingle) Latest(ctx context.Context) (*types.SignedTreeHead, error) {
- th, err := sm.client.GetTreeHead(ctx)
- if err != nil {
- return nil, fmt.Errorf("LatestTreeHead: %v", err)
- }
- th.KeyHash = types.Hash(sm.signer.Public().(ed25519.PublicKey)[:])
- sth, err := th.Sign(sm.signer)
- if err != nil {
- return nil, fmt.Errorf("sign: %v", err)
- }
- return sth, nil
-}
-
-func (sm *StateManagerSingle) ToSign(_ context.Context) (*types.SignedTreeHead, error) {
- sm.RLock()
- defer sm.RUnlock()
- return &sm.tosign, nil
-}
-
-func (sm *StateManagerSingle) Cosigned(_ context.Context) (*types.CosignedTreeHead, error) {
- sm.RLock()
- defer sm.RUnlock()
- if len(sm.cosigned.SigIdent) == 0 {
- return nil, fmt.Errorf("no witness cosignatures available")
- }
- return &sm.cosigned, nil
-}
-
-func (sm *StateManagerSingle) AddCosignature(_ context.Context, vk *[types.VerificationKeySize]byte, sig *[types.SignatureSize]byte) error {
- sm.Lock()
- defer sm.Unlock()
-
- if err := sm.tosign.TreeHead.Verify(vk, sig); err != nil {
- return fmt.Errorf("Verify: %v", err)
- }
- witness := types.Hash(vk[:])
- if _, ok := sm.cosignature[*witness]; ok {
- return fmt.Errorf("signature-signer pair is a duplicate")
- }
- sm.cosignature[*witness] = &types.SigIdent{
- Signature: sig,
- KeyHash: witness,
- }
-
- glog.V(3).Infof("accepted new cosignature from witness: %x", *witness)
- return nil
-}
-
-// rotate rotates the log's cosigned and stable STH. The caller must aquire the
-// source's read-write lock if there are concurrent reads and/or writes.
-func (sm *StateManagerSingle) rotate(next *types.SignedTreeHead) {
- if reflect.DeepEqual(sm.cosigned.SignedTreeHead, sm.tosign) {
- // cosigned and tosign are the same. So, we need to merge all
- // cosignatures that we already had with the new collected ones.
- for _, sigident := range sm.cosigned.SigIdent {
- if _, ok := sm.cosignature[*sigident.KeyHash]; !ok {
- sm.cosignature[*sigident.KeyHash] = sigident
- }
- }
- glog.V(3).Infof("cosigned tree head repeated, merged signatures")
- }
- var cosignatures []*types.SigIdent
- for _, sigident := range sm.cosignature {
- cosignatures = append(cosignatures, sigident)
- }
-
- // Update cosigned tree head
- sm.cosigned.SignedTreeHead = sm.tosign
- sm.cosigned.SigIdent = cosignatures
-
- // Update to-sign tree head
- sm.tosign = *next
- sm.cosignature = map[[types.HashSize]byte]*types.SigIdent{} // TODO: on repeat we might want to not zero this
- glog.V(3).Infof("rotated tree heads")
-}