diff --git a/internal/core/execute/v2/block/sig_authority_test.go b/internal/core/execute/v2/block/sig_authority_test.go new file mode 100644 index 000000000..e196743ca --- /dev/null +++ b/internal/core/execute/v2/block/sig_authority_test.go @@ -0,0 +1,114 @@ +// Copyright 2023 The Accumulate Authors +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +package block + +import ( + "crypto/ed25519" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + "gitlab.com/accumulatenetwork/accumulate/internal/core/execute" + "gitlab.com/accumulatenetwork/accumulate/internal/database" + "gitlab.com/accumulatenetwork/accumulate/internal/database/smt/storage" + "gitlab.com/accumulatenetwork/accumulate/pkg/build" + "gitlab.com/accumulatenetwork/accumulate/pkg/types/messaging" + "gitlab.com/accumulatenetwork/accumulate/pkg/url" + "gitlab.com/accumulatenetwork/accumulate/protocol" +) + +func TestDelegationPath(t *testing.T) { + var x AuthoritySignature + + alice := protocol.AccountUrl("alice") + bob := protocol.AccountUrl("bob") + bobKey := generateKey(bob) + charlie := protocol.AccountUrl("charlie") + charlieKey := generateKey(charlie) + david := protocol.AccountUrl("david") + davidKey := generateKey(david) + + type Path struct { + Path []*url.URL + Key ed25519.PrivateKey + } + cases := []struct { + Paths []Path + }{ + // One delegated, one direct + {Paths: []Path{ + {Path: []*url.URL{alice}, Key: bobKey}, + {Path: []*url.URL{alice, charlie}, Key: charlieKey}, + }}, + + // Both delegated, same path + {Paths: []Path{ + {Path: []*url.URL{alice, bob}, Key: bobKey}, + {Path: []*url.URL{alice, charlie}, Key: charlieKey}, + }}, + + // Both delegated, different paths + {Paths: []Path{ + {Path: []*url.URL{alice, bob, david}, Key: davidKey}, + {Path: []*url.URL{alice, charlie, david}, Key: davidKey}, + }}, + } + + block := &Block{ + Executor: &Executor{}, + } + + txn, err := build.Transaction().For(alice, "tokens").BurnTokens(1, 0). + Done() + require.NoError(t, err) + + // Run the tests + for i, c := range cases { + t.Run(fmt.Sprintf("Case %d", i+1), func(t *testing.T) { + db := database.OpenInMemory(nil) + db.SetObserver(execute.NewDatabaseObserver()) + batch := db.Begin(true) + defer batch.Discard() + + var ctx *SignatureContext + for _, path := range c.Paths { + sig := &protocol.AuthoritySignature{ + Origin: path.Path[len(path.Path)-1].JoinPath("book", "1"), + Authority: alice.JoinPath("book"), + Vote: protocol.VoteTypeAccept, + TxID: txn.ID(), + Cause: txn.ID(), // Don't care about the actual value + Delegator: path.Path[1:], + } + + ctx = &SignatureContext{ + MessageContext: &MessageContext{ + message: &messaging.SignatureMessage{ + Signature: sig, + TxID: txn.ID(), + }, + bundle: &bundle{Block: block}, + }, + signature: sig, + transaction: txn, + } + + status, err := x.Process(batch, ctx) + require.NoError(t, err) + require.NoError(t, status.AsError()) + } + + // The final signature should produce an authority signature + require.NotEmpty(t, ctx.produced) + }) + } +} + +func generateKey(seed ...interface{}) ed25519.PrivateKey { + h := storage.MakeKey(seed...) + return ed25519.NewKeyFromSeed(h[:]) +}