aboutsummaryrefslogtreecommitdiff
path: root/pkg/state/single_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/state/single_test.go')
-rw-r--r--pkg/state/single_test.go413
1 files changed, 106 insertions, 307 deletions
diff --git a/pkg/state/single_test.go b/pkg/state/single_test.go
index b315b3e..f619e2f 100644
--- a/pkg/state/single_test.go
+++ b/pkg/state/single_test.go
@@ -1,7 +1,6 @@
package state
import (
- "bytes"
"context"
"crypto"
"crypto/ed25519"
@@ -12,404 +11,204 @@ import (
"time"
"git.sigsum.org/sigsum-lib-go/pkg/types"
- mocksTrillian "git.sigsum.org/sigsum-log-go/pkg/db/mocks"
- mocksSigner "git.sigsum.org/sigsum-log-go/pkg/state/mocks"
+ db "git.sigsum.org/sigsum-log-go/pkg/db/mocks"
+ "git.sigsum.org/sigsum-log-go/pkg/state/mocks"
"github.com/golang/mock/gomock"
)
-var (
- testTH = types.TreeHead{
- Timestamp: 0,
- TreeSize: 0,
- RootHash: types.Hash{},
- }
- testSTH = types.SignedTreeHead{
- TreeHead: testTH,
- Signature: types.Signature{},
- }
- testCTH = types.CosignedTreeHead{
- SignedTreeHead: testSTH,
- Cosignature: []types.Signature{
- types.Signature{},
- },
- KeyHash: []types.Hash{
- types.Hash{},
- },
- }
-
- testSignerOK = &mocksSigner.TestSigner{types.PublicKey{}, types.Signature{}, nil}
- testSignerErr = &mocksSigner.TestSigner{types.PublicKey{}, types.Signature{}, fmt.Errorf("something went wrong")}
-)
-
func TestNewStateManagerSingle(t *testing.T) {
+ signerOk := &mocks.TestSigner{types.PublicKey{}, types.Signature{}, nil}
+ signerErr := &mocks.TestSigner{types.PublicKey{}, types.Signature{}, fmt.Errorf("err")}
for _, table := range []struct {
description string
signer crypto.Signer
- rsp *types.TreeHead
+ rsp types.TreeHead
err error
wantErr bool
- wantSth *types.SignedTreeHead
+ wantSth types.SignedTreeHead
}{
{
description: "invalid: backend failure",
- signer: testSignerOK,
+ signer: signerOk,
err: fmt.Errorf("something went wrong"),
wantErr: true,
},
{
- description: "valid",
- signer: testSignerOK,
- rsp: &testTH,
- wantSth: &testSTH,
- },
- } {
- // Run deferred functions at the end of each iteration
- func() {
- ctrl := gomock.NewController(t)
- defer ctrl.Finish()
- client := mocksTrillian.NewMockClient(ctrl)
- client.EXPECT().GetTreeHead(gomock.Any()).Return(table.rsp, table.err)
-
- sm, err := NewStateManagerSingle(client, table.signer, time.Duration(0), time.Duration(0))
- if got, want := err != nil, table.wantErr; got != want {
- t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err)
- }
- if err != nil {
- return
- }
- if got, want := &sm.cosigned.SignedTreeHead, table.wantSth; !reflect.DeepEqual(got, want) {
- t.Errorf("got cosigned tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)
- }
- if got, want := &sm.toSign, table.wantSth; !reflect.DeepEqual(got, want) {
- t.Errorf("got toSign tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)
- }
- // we only have log signature on startup
- if got, want := len(sm.cosignatures), 0; got != want {
- t.Errorf("got %d cosignatures but wanted %d in test %q", got, want, table.description)
- }
- }()
- }
-}
-
-func TestLatest(t *testing.T) {
- for _, table := range []struct {
- description string
- signer crypto.Signer
- rsp *types.TreeHead
- err error
- wantErr bool
- wantSth *types.SignedTreeHead
- }{
- {
- description: "invalid: backend failure",
- signer: testSignerOK,
- err: fmt.Errorf("something went wrong"),
- wantErr: true,
- },
- {
- description: "invalid: signature failure",
- rsp: &testTH,
- signer: testSignerErr,
+ description: "invalid: signer failure",
+ signer: signerErr,
+ rsp: types.TreeHead{},
wantErr: true,
},
{
description: "valid",
- signer: testSignerOK,
- rsp: &testTH,
- wantSth: &testSTH,
+ signer: signerOk,
+ rsp: types.TreeHead{},
+ wantSth: types.SignedTreeHead{},
},
} {
- // Run deferred functions at the end of each iteration
func() {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
- client := mocksTrillian.NewMockClient(ctrl)
- client.EXPECT().GetTreeHead(gomock.Any()).Return(table.rsp, table.err)
- sm := StateManagerSingle{
- client: client,
- signer: table.signer,
- }
+ client := db.NewMockClient(ctrl)
+ client.EXPECT().GetTreeHead(gomock.Any()).Return(&table.rsp, table.err)
- sth, err := sm.Latest(context.Background())
+ sm, err := NewStateManagerSingle(client, table.signer, time.Duration(0), time.Duration(0))
if got, want := err != nil, table.wantErr; got != want {
t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err)
}
if err != nil {
return
}
- if got, want := sth, table.wantSth; !reflect.DeepEqual(got, want) {
- t.Errorf("got signed tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)
+ if got, want := sm.signedTreeHead, &table.wantSth; !reflect.DeepEqual(got, want) {
+ t.Errorf("got to-cosign tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)
+ }
+ if got := sm.cosignedTreeHead; got != nil {
+ t.Errorf("got cosigned tree head but should have none in test %q", table.description)
}
}()
}
}
-func TestToSign(t *testing.T) {
- description := "valid"
+func TestToCosignTreeHead(t *testing.T) {
+ want := &types.SignedTreeHead{}
sm := StateManagerSingle{
- toSign: testSTH,
+ signedTreeHead: want,
}
- sth, err := sm.ToSign(context.Background())
+ sth, err := sm.ToCosignTreeHead(context.Background())
if err != nil {
- t.Errorf("ToSign should not fail with error: %v", err)
+ t.Errorf("should not fail with error: %v", err)
return
}
- if got, want := sth, &testSTH; !reflect.DeepEqual(got, want) {
- t.Errorf("got signed tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, description)
+ if got := sth; !reflect.DeepEqual(got, want) {
+ t.Errorf("got signed tree head\n\t%v\nbut wanted\n\t%v", got, want)
}
}
-func TestCosigned(t *testing.T) {
- description := "valid"
+func TestCosignedTreeHead(t *testing.T) {
+ want := &types.CosignedTreeHead{
+ Cosignature: make([]types.Signature, 1),
+ KeyHash: make([]types.Hash, 1),
+ }
sm := StateManagerSingle{
- cosigned: testCTH,
+ cosignedTreeHead: want,
}
- cth, err := sm.Cosigned(context.Background())
+ cth, err := sm.CosignedTreeHead(context.Background())
if err != nil {
- t.Errorf("Cosigned should not fail with error: %v", err)
+ t.Errorf("should not fail with error: %v", err)
return
}
- if got, want := cth, &testCTH; !reflect.DeepEqual(got, want) {
- t.Errorf("got signed tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, description)
+ if got := cth; !reflect.DeepEqual(got, want) {
+ t.Errorf("got cosigned tree head\n\t%v\nbut wanted\n\t%v", got, want)
}
- sm.cosigned.Cosignature = make([]types.Signature, 0)
- sm.cosigned.KeyHash = make([]types.Hash, 0)
- cth, err = sm.Cosigned(context.Background())
+ sm.cosignedTreeHead = nil
+ cth, err = sm.CosignedTreeHead(context.Background())
if err == nil {
- t.Errorf("Cosigned should fail without witness cosignatures")
+ t.Errorf("should fail without a cosigned tree head")
return
}
}
func TestAddCosignature(t *testing.T) {
- vk, sk, err := ed25519.GenerateKey(rand.Reader)
- if err != nil {
- t.Fatalf("GenerateKey: %v", err)
- }
- if bytes.Equal(vk[:], new(types.PublicKey)[:]) {
- t.Fatalf("Sampled same key as testPub, aborting...")
- }
- var vkArray types.PublicKey
- copy(vkArray[:], vk[:])
-
+ secret, public := mustKeyPair(t)
for _, table := range []struct {
- description string
- signer crypto.Signer
- vk types.PublicKey
- th types.TreeHead
- wantErr bool
+ desc string
+ signer crypto.Signer
+ vk types.PublicKey
+ wantErr bool
}{
{
- description: "invalid: signature error",
- signer: sk,
- vk: types.PublicKey{}, // wrong key for message
- th: testTH,
- wantErr: true,
+ desc: "invalid: wrong public key",
+ signer: secret,
+ vk: types.PublicKey{},
+ wantErr: true,
},
{
- description: "valid",
- signer: sk,
- vk: vkArray,
- th: testTH,
+ desc: "valid",
+ signer: secret,
+ vk: public,
},
} {
- kh := types.HashFn(testSignerOK.Public().(ed25519.PublicKey))
- sth := mustSign(t, testSignerOK, &table.th, kh)
- cth := &types.CosignedTreeHead{
- SignedTreeHead: *sth,
- Cosignature: make([]types.Signature, 0),
- KeyHash: make([]types.Hash, 0),
- }
sm := &StateManagerSingle{
- signer: testSignerOK,
- cosigned: *cth,
- toSign: *sth,
- cosignatures: make(map[types.Hash]*types.Signature, 0),
+ namespace: *types.HashFn(nil),
+ signedTreeHead: &types.SignedTreeHead{},
+ events: make(chan *event, 1),
}
+ defer close(sm.events)
- // Prepare witness signature
- var vk types.PublicKey
- copy(vk[:], table.vk[:]) //table.signer.Public().(ed25519.PublicKey))
- sth = mustSign(t, table.signer, &table.th, kh)
- kh = types.HashFn(vk[:])
-
- // Add witness signature
- err = sm.AddCosignature(context.Background(), &vk, &sth.Signature)
+ sth := mustSign(t, table.signer, &sm.signedTreeHead.TreeHead, &sm.namespace)
+ ctx := context.Background()
+ err := sm.AddCosignature(ctx, &table.vk, &sth.Signature)
if got, want := err != nil, table.wantErr; got != want {
- t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err)
+ t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.desc, err)
}
if err != nil {
continue
}
- // We should have one witness signature
- if got, want := len(sm.cosignatures), 1; got != want {
- t.Errorf("got %d cosignatures but wanted %v in test %q", got, want, table.description)
- continue
- }
- // check that witness signature is there
- sig, ok := sm.cosignatures[*kh]
- if !ok {
- t.Errorf("witness signature is missing")
- continue
+ ctx, cancel := context.WithTimeout(ctx, 50*time.Millisecond)
+ defer cancel()
+ if err := sm.AddCosignature(ctx, &table.vk, &sth.Signature); err == nil {
+ t.Errorf("expected full channel in test %q", table.desc)
}
- if got, want := sig[:], sth.Signature[:]; !bytes.Equal(got, want) {
- t.Errorf("got witness sigident\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)
- continue
- }
-
- // Adding a duplicate signature should give an error
- if err := sm.AddCosignature(context.Background(), &vk, &sth.Signature); err == nil {
- t.Errorf("duplicate witness signature accepted as valid")
+ if got, want := len(sm.events), 1; got != want {
+ t.Errorf("wanted %d cosignatures but got %d in test %q", want, got, table.desc)
}
}
}
func TestRotate(t *testing.T) {
- logSig := types.Signature{}
- wit1Sig := types.Signature{}
- wit2Sig := types.Signature{}
-
- //logKH := &types.Hash{}
- wit1KH := types.HashFn([]byte("wit1 key"))
- wit2KH := types.HashFn([]byte("wit2 key"))
+ sth := &types.SignedTreeHead{}
+ nextSTH := &types.SignedTreeHead{TreeHead: types.TreeHead{Timestamp: 1}}
+ ev := &event{
+ keyHash: &types.Hash{},
+ cosignature: &types.Signature{},
+ }
+ wantCTH := &types.CosignedTreeHead{
+ SignedTreeHead: *sth,
+ KeyHash: []types.Hash{*ev.keyHash},
+ Cosignature: []types.Signature{*ev.cosignature},
+ }
+ sm := &StateManagerSingle{
+ signedTreeHead: sth,
+ cosignatures: make(map[types.Hash]*types.Signature),
+ events: make(chan *event, 1),
+ }
+ defer close(sm.events)
- th0 := &testTH
- th1 := &types.TreeHead{
- Timestamp: 1,
- TreeSize: 1,
- RootHash: *types.HashFn([]byte("1")),
+ sm.events <- ev
+ sm.rotate(nextSTH)
+ if got, want := sm.signedTreeHead, nextSTH; !reflect.DeepEqual(got, want) {
+ t.Errorf("got to-cosign tree head\n\t%v\nbut wanted\n\t%v", got, want)
}
- th2 := &types.TreeHead{
- Timestamp: 2,
- TreeSize: 2,
- RootHash: *types.HashFn([]byte("2")),
+ if got, want := sm.cosignedTreeHead, wantCTH; !reflect.DeepEqual(got, want) {
+ t.Errorf("got cosigned tree head\n\t%v\nbut wanted\n\t%v", got, want)
}
- for _, table := range []struct {
- description string
- before, after *StateManagerSingle
- next *types.SignedTreeHead
- }{
- {
- description: "toSign tree head repated, but got one new witnes signature",
- before: &StateManagerSingle{
- cosigned: types.CosignedTreeHead{
- SignedTreeHead: types.SignedTreeHead{
- TreeHead: *th0,
- Signature: logSig,
- },
- Cosignature: []types.Signature{wit1Sig},
- KeyHash: []types.Hash{*wit1KH},
- },
- toSign: types.SignedTreeHead{
- TreeHead: *th0,
- Signature: logSig,
- },
- cosignatures: map[types.Hash]*types.Signature{
- *wit2KH: &wit2Sig, // the new witness signature
- },
- },
- next: &types.SignedTreeHead{
- TreeHead: *th1,
- Signature: logSig,
- },
- after: &StateManagerSingle{
- cosigned: types.CosignedTreeHead{
- SignedTreeHead: types.SignedTreeHead{
- TreeHead: *th0,
- Signature: logSig,
- },
- Cosignature: []types.Signature{wit1Sig, wit2Sig},
- KeyHash: []types.Hash{*wit1KH, *wit2KH},
- },
- toSign: types.SignedTreeHead{
- TreeHead: *th1,
- Signature: logSig,
- },
- cosignatures: map[types.Hash]*types.Signature{},
- },
- },
- {
- description: "toSign tree head did not repeat, it got one witness signature",
- before: &StateManagerSingle{
- cosigned: types.CosignedTreeHead{
- SignedTreeHead: types.SignedTreeHead{
- TreeHead: *th0,
- Signature: logSig,
- },
- Cosignature: []types.Signature{wit1Sig},
- KeyHash: []types.Hash{*wit1KH},
- },
- toSign: types.SignedTreeHead{
- TreeHead: *th1,
- Signature: logSig,
- },
- cosignatures: map[types.Hash]*types.Signature{
- *wit2KH: &wit2Sig,
- },
- },
- next: &types.SignedTreeHead{
- TreeHead: *th2,
- Signature: logSig,
- },
- after: &StateManagerSingle{
- cosigned: types.CosignedTreeHead{
- SignedTreeHead: types.SignedTreeHead{
- TreeHead: *th1,
- Signature: logSig,
- },
- Cosignature: []types.Signature{wit2Sig},
- KeyHash: []types.Hash{*wit2KH},
- },
- toSign: types.SignedTreeHead{
- TreeHead: *th2,
- Signature: logSig,
- },
- cosignatures: map[types.Hash]*types.Signature{},
- },
- },
- } {
- table.before.rotate(table.next)
- if got, want := table.before.cosigned.SignedTreeHead, table.after.cosigned.SignedTreeHead; !reflect.DeepEqual(got, want) {
- t.Errorf("got cosigned tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)
- }
- checkWitnessList(t, table.description, table.before.cosigned, table.after.cosigned)
- if got, want := table.before.toSign, table.after.toSign; !reflect.DeepEqual(got, want) {
- t.Errorf("got toSign tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)
- }
- if got, want := table.before.cosignatures, table.after.cosignatures; !reflect.DeepEqual(got, want) {
- t.Errorf("got cosignatures map\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)
- }
+ sth = nextSTH
+ nextSTH = &types.SignedTreeHead{TreeHead: types.TreeHead{Timestamp: 2}}
+ sm.rotate(nextSTH)
+ if got, want := sm.signedTreeHead, nextSTH; !reflect.DeepEqual(got, want) {
+ t.Errorf("got to-cosign tree head\n\t%v\nbut wanted\n\t%v", got, want)
+ }
+ if got := sm.cosignedTreeHead; got != nil {
+ t.Errorf("expected no cosignatures to be available")
}
}
-func checkWitnessList(t *testing.T, description string, got, want types.CosignedTreeHead) {
+func mustKeyPair(t *testing.T) (crypto.Signer, types.PublicKey) {
t.Helper()
- if got, want := len(got.Cosignature), len(want.Cosignature); got != want {
- t.Errorf("got %d cosignatures but wanted %d in test %q", got, want, description)
- return
- }
- if got, want := len(got.KeyHash), len(want.KeyHash); got != want {
- t.Errorf("got %d key hashes but wanted %d in test %q", got, want, description)
- return
- }
- for i := 0; i < len(got.Cosignature); i++ {
- found := false
- for j := 0; j < len(want.Cosignature); j++ {
- if bytes.Equal(got.Cosignature[i][:], want.Cosignature[j][:]) && bytes.Equal(got.KeyHash[i][:], want.KeyHash[j][:]) {
- found = true
- break
- }
- }
- if !found {
- t.Errorf("got unexpected signature-signer pair with key hash in test %q: %x", description, got.KeyHash[i][:])
- }
+ vk, sk, err := ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatal(err)
}
+ var pub types.PublicKey
+ copy(pub[:], vk[:])
+ return sk, pub
}
func mustSign(t *testing.T, s crypto.Signer, th *types.TreeHead, kh *types.Hash) *types.SignedTreeHead {
+ t.Helper()
sth, err := th.Sign(s, kh)
if err != nil {
t.Fatal(err)