From 7d4e45d02996561e365f820b67a1c4d8d622dda5 Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Fri, 22 Nov 2024 17:10:29 +0100 Subject: [PATCH 01/10] tests: add pre-allocated local authFactories --- examples/morpheusvm/tests/transfer.go | 41 +++++++++---------- examples/morpheusvm/tests/workload/genesis.go | 7 +++- tests/integration/integration.go | 2 +- tests/registry/registry.go | 35 ++++++++++++---- 4 files changed, 52 insertions(+), 33 deletions(-) diff --git a/examples/morpheusvm/tests/transfer.go b/examples/morpheusvm/tests/transfer.go index 11d3387437..a2ac8975f6 100644 --- a/examples/morpheusvm/tests/transfer.go +++ b/examples/morpheusvm/tests/transfer.go @@ -9,9 +9,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/ava-labs/hypersdk/auth" "github.com/ava-labs/hypersdk/chain" - "github.com/ava-labs/hypersdk/crypto/ed25519" "github.com/ava-labs/hypersdk/examples/morpheusvm/actions" "github.com/ava-labs/hypersdk/tests/registry" @@ -24,23 +22,22 @@ import ( // ref https://onsi.github.io/ginkgo/#mental-model-how-ginkgo-traverses-the-spec-hierarchy var TestsRegistry = ®istry.Registry{} -var _ = registry.Register(TestsRegistry, "Transfer Transaction", func(t ginkgo.FullGinkgoTInterface, tn tworkload.TestNetwork) { - require := require.New(t) - other, err := ed25519.GeneratePrivateKey() - require.NoError(err) - toAddress := auth.NewED25519Address(other.PublicKey()) - - authFactory := tn.Configuration().AuthFactories()[0] - tx, err := tn.GenerateTx(context.Background(), []chain.Action{&actions.Transfer{ - To: toAddress, - Value: 1, - }}, - authFactory, - ) - require.NoError(err) - - timeoutCtx, timeoutCtxFnc := context.WithDeadline(context.Background(), time.Now().Add(30*time.Second)) - defer timeoutCtxFnc() - - require.NoError(tn.ConfirmTxs(timeoutCtx, []*chain.Transaction{tx})) -}) +var _ = registry.Register(TestsRegistry, "Transfer Transaction", + func(t ginkgo.FullGinkgoTInterface, tn tworkload.TestNetwork, authFactories ...chain.AuthFactory) { + require := require.New(t) + targetFactory := authFactories[0] + + authFactory := tn.Configuration().AuthFactories()[0] + tx, err := tn.GenerateTx(context.Background(), []chain.Action{&actions.Transfer{ + To: targetFactory.Address(), + Value: 1, + }}, + authFactory, + ) + require.NoError(err) + + timeoutCtx, timeoutCtxFnc := context.WithDeadline(context.Background(), time.Now().Add(30*time.Second)) + defer timeoutCtxFnc() + + require.NoError(tn.ConfirmTxs(timeoutCtx, []*chain.Transaction{tx})) + }, 1000) diff --git a/examples/morpheusvm/tests/workload/genesis.go b/examples/morpheusvm/tests/workload/genesis.go index dcc78252a9..c9be92423f 100644 --- a/examples/morpheusvm/tests/workload/genesis.go +++ b/examples/morpheusvm/tests/workload/genesis.go @@ -15,6 +15,7 @@ import ( "github.com/ava-labs/hypersdk/codec" "github.com/ava-labs/hypersdk/crypto/ed25519" "github.com/ava-labs/hypersdk/examples/morpheusvm/consts" + "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" "github.com/ava-labs/hypersdk/examples/morpheusvm/vm" "github.com/ava-labs/hypersdk/fees" "github.com/ava-labs/hypersdk/genesis" @@ -32,7 +33,7 @@ var ed25519HexKeys = []string{ "8a7be2e0c9a2d09ac2861c34326d6fe5a461d920ba9c2b345ae28e603d517df148735063f8d5d8ba79ea4668358943e5c80bc09e9b2b9a15b5b15db6c1862e88", //nolint:lll } -func newGenesis(authFactories []chain.AuthFactory, minBlockGap time.Duration) *genesis.DefaultGenesis { +func newGenesis(authFactories []chain.AuthFactory, testsLocalAllocations []*genesis.CustomAllocation, minBlockGap time.Duration) *genesis.DefaultGenesis { // allocate the initial balance to the addresses customAllocs := make([]*genesis.CustomAllocation, 0, len(authFactories)) for _, authFactory := range authFactories { @@ -41,6 +42,7 @@ func newGenesis(authFactories []chain.AuthFactory, minBlockGap time.Duration) *g Balance: InitialBalance, }) } + customAllocs = append(customAllocs, testsLocalAllocations...) genesis := genesis.NewDefaultGenesis(customAllocs) @@ -72,7 +74,8 @@ func newDefaultAuthFactories() []chain.AuthFactory { func NewTestNetworkConfig(minBlockGap time.Duration) (workload.DefaultTestNetworkConfiguration, error) { keys := newDefaultAuthFactories() - genesis := newGenesis(keys, minBlockGap) + testsLocalAllocations := tests.TestsRegistry.GetRequestedAllocations() + genesis := newGenesis(keys, testsLocalAllocations, minBlockGap) genesisBytes, err := json.Marshal(genesis) if err != nil { return workload.DefaultTestNetworkConfiguration{}, err diff --git a/tests/integration/integration.go b/tests/integration/integration.go index 85d67f41fd..29d796183b 100644 --- a/tests/integration/integration.go +++ b/tests/integration/integration.go @@ -624,7 +624,7 @@ var _ = ginkgo.Describe("[Tx Processing]", ginkgo.Serial, func() { for _, test := range testRegistry.List() { ginkgo.It(fmt.Sprintf("Custom VM Test '%s'", test.Name), func() { require.NoError(testNetwork.SynchronizeNetwork(context.Background())) - test.Fnc(ginkgo.GinkgoT(), testNetwork) + test.Fnc(ginkgo.GinkgoT(), testNetwork, test.AuthFactories...) }) } } diff --git a/tests/registry/registry.go b/tests/registry/registry.go index 55c6e9cae2..162d2b526c 100644 --- a/tests/registry/registry.go +++ b/tests/registry/registry.go @@ -6,21 +6,36 @@ package registry import ( "github.com/onsi/ginkgo/v2" + "github.com/ava-labs/hypersdk/auth" + "github.com/ava-labs/hypersdk/chain" + "github.com/ava-labs/hypersdk/crypto/ed25519" + "github.com/ava-labs/hypersdk/genesis" "github.com/ava-labs/hypersdk/tests/workload" ) -type TestFunc func(t ginkgo.FullGinkgoTInterface, tn workload.TestNetwork) +type TestFunc func(t ginkgo.FullGinkgoTInterface, tn workload.TestNetwork, authFactories ...chain.AuthFactory) type namedTest struct { - Fnc TestFunc - Name string + Fnc TestFunc + Name string + AuthFactories []chain.AuthFactory } type Registry struct { - tests []namedTest + tests []namedTest + requestedAllocations []*genesis.CustomAllocation } -func (r *Registry) Add(name string, f TestFunc) { - r.tests = append(r.tests, namedTest{Fnc: f, Name: name}) +func (r *Registry) Add(name string, f TestFunc, requestedBalances ...uint64) { + allocations := make([]*genesis.CustomAllocation, 0, len(requestedBalances)) + authFactories := make([]chain.AuthFactory, 0, len(requestedBalances)) + for _, requestedBalance := range requestedBalances { + private, _ := ed25519.GeneratePrivateKey() + authFactory := auth.NewED25519Factory(private) + authFactories = append(authFactories, authFactory) + allocations = append(allocations, &genesis.CustomAllocation{Address: authFactory.Address(), Balance: requestedBalance}) + } + r.tests = append(r.tests, namedTest{Fnc: f, Name: name, AuthFactories: authFactories}) + r.requestedAllocations = append(r.requestedAllocations, allocations...) } func (r *Registry) List() []namedTest { @@ -30,13 +45,17 @@ func (r *Registry) List() []namedTest { return r.tests } +func (r *Registry) GetRequestedAllocations() []*genesis.CustomAllocation { + return r.requestedAllocations +} + // we need to pre-register all the test registries that are created externally in order to comply with the ginko execution order. // i.e. the global `var _ = ginkgo.Describe` used in the integration/e2e tests need to have this field populated before the iteration // over the top level nodes. var testRegistries = map[*Registry]bool{} -func Register(registry *Registry, name string, f TestFunc) bool { - registry.Add(name, f) +func Register(registry *Registry, name string, f TestFunc, requestedBalances ...uint64) bool { + registry.Add(name, f, requestedBalances...) testRegistries[registry] = true return true } From 7801685033b48e780730d3a5a42506ae2191460b Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Fri, 22 Nov 2024 18:05:09 +0100 Subject: [PATCH 02/10] tests: delay pre-allocated local authFactories initialization --- examples/morpheusvm/tests/workload/genesis.go | 11 ++++- tests/e2e/e2e.go | 2 +- tests/registry/registry.go | 49 +++++++++++-------- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/examples/morpheusvm/tests/workload/genesis.go b/examples/morpheusvm/tests/workload/genesis.go index c9be92423f..325723d468 100644 --- a/examples/morpheusvm/tests/workload/genesis.go +++ b/examples/morpheusvm/tests/workload/genesis.go @@ -74,7 +74,16 @@ func newDefaultAuthFactories() []chain.AuthFactory { func NewTestNetworkConfig(minBlockGap time.Duration) (workload.DefaultTestNetworkConfiguration, error) { keys := newDefaultAuthFactories() - testsLocalAllocations := tests.TestsRegistry.GetRequestedAllocations() + testsLocalAllocations, err := tests.TestsRegistry.GenerateCustomAllocations(func() (chain.AuthFactory, error) { + privateKey, err := ed25519.GeneratePrivateKey() + if err != nil { + return nil, err + } + return auth.NewED25519Factory(privateKey), nil + }) + if err != nil { + return workload.DefaultTestNetworkConfiguration{}, err + } genesis := newGenesis(keys, testsLocalAllocations, minBlockGap) genesisBytes, err := json.Marshal(genesis) if err != nil { diff --git a/tests/e2e/e2e.go b/tests/e2e/e2e.go index f998f6ca72..2aced9d920 100644 --- a/tests/e2e/e2e.go +++ b/tests/e2e/e2e.go @@ -249,7 +249,7 @@ var _ = ginkgo.Describe("[Custom VM Tests]", ginkgo.Serial, func() { for _, test := range testRegistry.List() { ginkgo.It(test.Name, func() { testNetwork := NewNetwork(tc) - test.Fnc(ginkgo.GinkgoT(), testNetwork) + test.Fnc(ginkgo.GinkgoT(), testNetwork, test.AuthFactories...) }) } } diff --git a/tests/registry/registry.go b/tests/registry/registry.go index 162d2b526c..f4cfcc37d5 100644 --- a/tests/registry/registry.go +++ b/tests/registry/registry.go @@ -6,9 +6,7 @@ package registry import ( "github.com/onsi/ginkgo/v2" - "github.com/ava-labs/hypersdk/auth" "github.com/ava-labs/hypersdk/chain" - "github.com/ava-labs/hypersdk/crypto/ed25519" "github.com/ava-labs/hypersdk/genesis" "github.com/ava-labs/hypersdk/tests/workload" ) @@ -16,37 +14,46 @@ import ( type TestFunc func(t ginkgo.FullGinkgoTInterface, tn workload.TestNetwork, authFactories ...chain.AuthFactory) type namedTest struct { - Fnc TestFunc - Name string - AuthFactories []chain.AuthFactory + Fnc TestFunc + Name string + AuthFactories []chain.AuthFactory + requestedBalances []uint64 } type Registry struct { - tests []namedTest - requestedAllocations []*genesis.CustomAllocation + tests []*namedTest } func (r *Registry) Add(name string, f TestFunc, requestedBalances ...uint64) { - allocations := make([]*genesis.CustomAllocation, 0, len(requestedBalances)) - authFactories := make([]chain.AuthFactory, 0, len(requestedBalances)) - for _, requestedBalance := range requestedBalances { - private, _ := ed25519.GeneratePrivateKey() - authFactory := auth.NewED25519Factory(private) - authFactories = append(authFactories, authFactory) - allocations = append(allocations, &genesis.CustomAllocation{Address: authFactory.Address(), Balance: requestedBalance}) - } - r.tests = append(r.tests, namedTest{Fnc: f, Name: name, AuthFactories: authFactories}) - r.requestedAllocations = append(r.requestedAllocations, allocations...) + r.tests = append(r.tests, &namedTest{Fnc: f, Name: name, requestedBalances: requestedBalances}) } -func (r *Registry) List() []namedTest { +func (r *Registry) List() []*namedTest { if r == nil { - return []namedTest{} + return []*namedTest{} } return r.tests } -func (r *Registry) GetRequestedAllocations() []*genesis.CustomAllocation { - return r.requestedAllocations +func (r *Registry) GenerateCustomAllocations(generateAuthFactory func() (chain.AuthFactory, error)) ([]*genesis.CustomAllocation, error) { + requestedAllocations := make([]*genesis.CustomAllocation, 0) + for index, test := range r.tests { + for _, requestedBalance := range test.requestedBalances { + authFactory, err := generateAuthFactory() + if err != nil { + return nil, err + } + test.AuthFactories = append(test.AuthFactories, authFactory) + requestedAllocations = append( + requestedAllocations, + &genesis.CustomAllocation{ + Address: authFactory.Address(), + Balance: requestedBalance, + }, + ) + } + r.tests[index] = test + } + return requestedAllocations, nil } // we need to pre-register all the test registries that are created externally in order to comply with the ginko execution order. From cbb5a7f6f6ff08f6c7a48c688420c0acad7dd810 Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Fri, 22 Nov 2024 18:07:14 +0100 Subject: [PATCH 03/10] tests: add example of interacting with URIs --- examples/morpheusvm/tests/transfer.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/morpheusvm/tests/transfer.go b/examples/morpheusvm/tests/transfer.go index a2ac8975f6..4f7947a7d1 100644 --- a/examples/morpheusvm/tests/transfer.go +++ b/examples/morpheusvm/tests/transfer.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/ava-labs/hypersdk/api/jsonrpc" "github.com/ava-labs/hypersdk/chain" "github.com/ava-labs/hypersdk/examples/morpheusvm/actions" "github.com/ava-labs/hypersdk/tests/registry" @@ -27,6 +28,11 @@ var _ = registry.Register(TestsRegistry, "Transfer Transaction", require := require.New(t) targetFactory := authFactories[0] + client := jsonrpc.NewJSONRPCClient(tn.URIs()[0]) + balance, err := client.GetBalance(context.Background(), targetFactory.Address()) + require.NoError(err) + require.Equal(uint64(1000), balance) + authFactory := tn.Configuration().AuthFactories()[0] tx, err := tn.GenerateTx(context.Background(), []chain.Action{&actions.Transfer{ To: targetFactory.Address(), @@ -38,6 +44,9 @@ var _ = registry.Register(TestsRegistry, "Transfer Transaction", timeoutCtx, timeoutCtxFnc := context.WithDeadline(context.Background(), time.Now().Add(30*time.Second)) defer timeoutCtxFnc() - require.NoError(tn.ConfirmTxs(timeoutCtx, []*chain.Transaction{tx})) + + balance, err = client.GetBalance(context.Background(), targetFactory.Address()) + require.NoError(err) + require.Equal(uint64(1001), balance) }, 1000) From 09f80bee3127e17550ff4c6a9ede2e8f9d7f9b9c Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Fri, 22 Nov 2024 18:25:18 +0100 Subject: [PATCH 04/10] update tests doc --- docs/tutorials/morpheusvm/4_testing.md | 28 +++++++++++++++++--------- examples/morpheusvm/tests/transfer.go | 9 +++++---- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/docs/tutorials/morpheusvm/4_testing.md b/docs/tutorials/morpheusvm/4_testing.md index 5017ac4377..3f36d3437d 100644 --- a/docs/tutorials/morpheusvm/4_testing.md +++ b/docs/tutorials/morpheusvm/4_testing.md @@ -362,30 +362,34 @@ registry of all the tests that we want to run against our VM. Afterwards, we have the following snippet: ```go -registry.Register(TestsRegistry, "Transfer Transaction", func(t ginkgo.FullGinkgoTInterface, tn tworkload.TestNetwork) { +registry.Register(TestsRegistry, "Transfer Transaction", func(t ginkgo.FullGinkgoTInterface, tn tworkload.TestNetwork, authFactories ...chain.AuthFactory) { -}) +}, 1000) ``` -Here, we are adding a test to `TestRegistry`. However, we're +Here, we are adding a test to `TestRegistry`, requesting an authFactory to be funded with 1000 tokens. However, we're missing the test itself. In short, here's what we want to do in our testing logic: -- Setup necessary values +- Setup necessary values & Check the funds of the requested authFactory - Create our test TX - Send our TX - Require that our TX is sent and that the outputs are as expected +- Check the receiver has received the funds Focusing on the first step, we can write the following inside the anonymous function: ```go require := require.New(t) - other, err := ed25519.GeneratePrivateKey() - require.NoError(err) - toAddress := auth.NewED25519Address(other.PublicKey()) - + ctx := context.Background() + targetFactory := authFactories[0] authFactory := tn.Configuration().AuthFactories()[0] + + client := jsonrpc.NewJSONRPCClient(tn.URIs()[0]) + balance, err := client.GetBalance(ctx, targetFactory.Address()) + require.NoError(err) + require.Equal(uint64(1000), balance) ``` Next, we'll create our test transaction. In short, we'll want to send a value of @@ -401,12 +405,13 @@ Next, we'll create our test transaction. In short, we'll want to send a value of require.NoError(err) ``` -Finally, we'll want to send our TX and do the checks mentioned in the last step. +Finally, we'll want to send our TX, check that the Tx has been executed and receiver has received the amount of token. This step will consist of the following: - Creating a context with a deadline of 2 seconds - If the test takes longer than 2 seconds, it will fail - Calling `ConfirmTxs` with our TX being passed in +- Requesting the balance The function `ConfirmTXs` is useful as it checks that our TX was sent and that, if finalized, our transaction has the expected outputs. We have @@ -415,8 +420,11 @@ the following: ```go timeoutCtx, timeoutCtxFnc := context.WithDeadline(context.Background(), time.Now().Add(30*time.Second)) defer timeoutCtxFnc() - require.NoError(tn.ConfirmTxs(timeoutCtx, []*chain.Transaction{tx})) + + balance, err = client.GetBalance(context.Background(), targetFactory.Address()) + require.NoError(err) + require.Equal(uint64(1001), balance) ``` ## Registering our Tests diff --git a/examples/morpheusvm/tests/transfer.go b/examples/morpheusvm/tests/transfer.go index 4f7947a7d1..a9b22c8c81 100644 --- a/examples/morpheusvm/tests/transfer.go +++ b/examples/morpheusvm/tests/transfer.go @@ -26,15 +26,16 @@ var TestsRegistry = ®istry.Registry{} var _ = registry.Register(TestsRegistry, "Transfer Transaction", func(t ginkgo.FullGinkgoTInterface, tn tworkload.TestNetwork, authFactories ...chain.AuthFactory) { require := require.New(t) + ctx := context.Background() targetFactory := authFactories[0] + authFactory := tn.Configuration().AuthFactories()[0] client := jsonrpc.NewJSONRPCClient(tn.URIs()[0]) - balance, err := client.GetBalance(context.Background(), targetFactory.Address()) + balance, err := client.GetBalance(ctx, targetFactory.Address()) require.NoError(err) require.Equal(uint64(1000), balance) - authFactory := tn.Configuration().AuthFactories()[0] - tx, err := tn.GenerateTx(context.Background(), []chain.Action{&actions.Transfer{ + tx, err := tn.GenerateTx(ctx, []chain.Action{&actions.Transfer{ To: targetFactory.Address(), Value: 1, }}, @@ -46,7 +47,7 @@ var _ = registry.Register(TestsRegistry, "Transfer Transaction", defer timeoutCtxFnc() require.NoError(tn.ConfirmTxs(timeoutCtx, []*chain.Transaction{tx})) - balance, err = client.GetBalance(context.Background(), targetFactory.Address()) + balance, err = client.GetBalance(ctx, targetFactory.Address()) require.NoError(err) require.Equal(uint64(1001), balance) }, 1000) From 601348ef342626193600d7a866ffe3d6e1b39302 Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Wed, 27 Nov 2024 12:21:01 +0100 Subject: [PATCH 05/10] morpheusvm: move helper function into auth package --- auth/ed25519.go | 8 ++++++++ examples/morpheusvm/tests/workload/genesis.go | 8 +------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/auth/ed25519.go b/auth/ed25519.go index 6546ad7dd3..485053fff6 100644 --- a/auth/ed25519.go +++ b/auth/ed25519.go @@ -102,6 +102,14 @@ func (d *ED25519Factory) Address() codec.Address { return NewED25519Address(d.priv.PublicKey()) } +func GenerateED25519AuthFactory() (chain.AuthFactory, error) { + privateKey, err := ed25519.GeneratePrivateKey() + if err != nil { + return nil, err + } + return NewED25519Factory(privateKey), nil +} + type ED25519AuthEngine struct{} func (*ED25519AuthEngine) GetBatchVerifier(cores int, count int) chain.AuthBatchVerifier { diff --git a/examples/morpheusvm/tests/workload/genesis.go b/examples/morpheusvm/tests/workload/genesis.go index 325723d468..d7af04b082 100644 --- a/examples/morpheusvm/tests/workload/genesis.go +++ b/examples/morpheusvm/tests/workload/genesis.go @@ -74,13 +74,7 @@ func newDefaultAuthFactories() []chain.AuthFactory { func NewTestNetworkConfig(minBlockGap time.Duration) (workload.DefaultTestNetworkConfiguration, error) { keys := newDefaultAuthFactories() - testsLocalAllocations, err := tests.TestsRegistry.GenerateCustomAllocations(func() (chain.AuthFactory, error) { - privateKey, err := ed25519.GeneratePrivateKey() - if err != nil { - return nil, err - } - return auth.NewED25519Factory(privateKey), nil - }) + testsLocalAllocations, err := tests.TestsRegistry.GenerateCustomAllocations(auth.GenerateED25519AuthFactory) if err != nil { return workload.DefaultTestNetworkConfiguration{}, err } From d34c08d86e5c79348f54e7a70bf144cd975e9990 Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Wed, 27 Nov 2024 12:26:29 +0100 Subject: [PATCH 06/10] tests: remove syntactic sugar --- examples/morpheusvm/tests/transfer.go | 2 +- tests/registry/registry.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/morpheusvm/tests/transfer.go b/examples/morpheusvm/tests/transfer.go index a9b22c8c81..29e42694c4 100644 --- a/examples/morpheusvm/tests/transfer.go +++ b/examples/morpheusvm/tests/transfer.go @@ -24,7 +24,7 @@ import ( var TestsRegistry = ®istry.Registry{} var _ = registry.Register(TestsRegistry, "Transfer Transaction", - func(t ginkgo.FullGinkgoTInterface, tn tworkload.TestNetwork, authFactories ...chain.AuthFactory) { + func(t ginkgo.FullGinkgoTInterface, tn tworkload.TestNetwork, authFactories []chain.AuthFactory) { require := require.New(t) ctx := context.Background() targetFactory := authFactories[0] diff --git a/tests/registry/registry.go b/tests/registry/registry.go index f4cfcc37d5..88818065e9 100644 --- a/tests/registry/registry.go +++ b/tests/registry/registry.go @@ -11,7 +11,7 @@ import ( "github.com/ava-labs/hypersdk/tests/workload" ) -type TestFunc func(t ginkgo.FullGinkgoTInterface, tn workload.TestNetwork, authFactories ...chain.AuthFactory) +type TestFunc func(t ginkgo.FullGinkgoTInterface, tn workload.TestNetwork, authFactories []chain.AuthFactory) type namedTest struct { Fnc TestFunc From 42d6ce8e57665c468df1d87e3be9716bb77bae99 Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Wed, 27 Nov 2024 12:36:21 +0100 Subject: [PATCH 07/10] tests: move custom allocation generation into tests entrypoints --- examples/morpheusvm/tests/e2e/e2e_test.go | 5 ++++- .../morpheusvm/tests/integration/integration_test.go | 5 ++++- examples/morpheusvm/tests/workload/genesis.go | 9 ++------- tests/e2e/e2e.go | 2 +- tests/integration/integration.go | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/examples/morpheusvm/tests/e2e/e2e_test.go b/examples/morpheusvm/tests/e2e/e2e_test.go index e747f7766e..8261a9c3e9 100644 --- a/examples/morpheusvm/tests/e2e/e2e_test.go +++ b/examples/morpheusvm/tests/e2e/e2e_test.go @@ -10,6 +10,7 @@ import ( "github.com/ava-labs/avalanchego/tests/fixture/e2e" "github.com/stretchr/testify/require" + "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" _ "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" // include the tests that are shared between the integration and e2e "github.com/ava-labs/hypersdk/abi" @@ -40,7 +41,9 @@ func init() { var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { require := require.New(ginkgo.GinkgoT()) - testingNetworkConfig, err := workload.NewTestNetworkConfig(100 * time.Millisecond) + customAllocs, err := tests.TestsRegistry.GenerateCustomAllocations(auth.GenerateED25519AuthFactory) + require.NoError(err) + testingNetworkConfig, err := workload.NewTestNetworkConfig(100*time.Millisecond, customAllocs) require.NoError(err) expectedABI, err := abi.NewABI(vm.ActionParser.GetRegisteredTypes(), vm.OutputParser.GetRegisteredTypes()) diff --git a/examples/morpheusvm/tests/integration/integration_test.go b/examples/morpheusvm/tests/integration/integration_test.go index f616b2939e..d00fdc7b11 100644 --- a/examples/morpheusvm/tests/integration/integration_test.go +++ b/examples/morpheusvm/tests/integration/integration_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" _ "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" // include the tests that are shared between the integration and e2e "github.com/ava-labs/hypersdk/auth" @@ -27,7 +28,9 @@ func TestIntegration(t *testing.T) { var _ = ginkgo.BeforeSuite(func() { require := require.New(ginkgo.GinkgoT()) - testingNetworkConfig, err := workload.NewTestNetworkConfig(0) + customAllocs, err := tests.TestsRegistry.GenerateCustomAllocations(auth.GenerateED25519AuthFactory) + require.NoError(err) + testingNetworkConfig, err := workload.NewTestNetworkConfig(0, customAllocs) require.NoError(err) randomEd25519Priv, err := ed25519.GeneratePrivateKey() diff --git a/examples/morpheusvm/tests/workload/genesis.go b/examples/morpheusvm/tests/workload/genesis.go index d7af04b082..b4ba5a9f56 100644 --- a/examples/morpheusvm/tests/workload/genesis.go +++ b/examples/morpheusvm/tests/workload/genesis.go @@ -15,7 +15,6 @@ import ( "github.com/ava-labs/hypersdk/codec" "github.com/ava-labs/hypersdk/crypto/ed25519" "github.com/ava-labs/hypersdk/examples/morpheusvm/consts" - "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" "github.com/ava-labs/hypersdk/examples/morpheusvm/vm" "github.com/ava-labs/hypersdk/fees" "github.com/ava-labs/hypersdk/genesis" @@ -72,13 +71,9 @@ func newDefaultAuthFactories() []chain.AuthFactory { return authFactories } -func NewTestNetworkConfig(minBlockGap time.Duration) (workload.DefaultTestNetworkConfiguration, error) { +func NewTestNetworkConfig(minBlockGap time.Duration, customAllocs []*genesis.CustomAllocation) (workload.DefaultTestNetworkConfiguration, error) { keys := newDefaultAuthFactories() - testsLocalAllocations, err := tests.TestsRegistry.GenerateCustomAllocations(auth.GenerateED25519AuthFactory) - if err != nil { - return workload.DefaultTestNetworkConfiguration{}, err - } - genesis := newGenesis(keys, testsLocalAllocations, minBlockGap) + genesis := newGenesis(keys, customAllocs, minBlockGap) genesisBytes, err := json.Marshal(genesis) if err != nil { return workload.DefaultTestNetworkConfiguration{}, err diff --git a/tests/e2e/e2e.go b/tests/e2e/e2e.go index 2aced9d920..d38db2a116 100644 --- a/tests/e2e/e2e.go +++ b/tests/e2e/e2e.go @@ -249,7 +249,7 @@ var _ = ginkgo.Describe("[Custom VM Tests]", ginkgo.Serial, func() { for _, test := range testRegistry.List() { ginkgo.It(test.Name, func() { testNetwork := NewNetwork(tc) - test.Fnc(ginkgo.GinkgoT(), testNetwork, test.AuthFactories...) + test.Fnc(ginkgo.GinkgoT(), testNetwork, test.AuthFactories) }) } } diff --git a/tests/integration/integration.go b/tests/integration/integration.go index 8286b97c64..22e7f11a76 100644 --- a/tests/integration/integration.go +++ b/tests/integration/integration.go @@ -624,7 +624,7 @@ var _ = ginkgo.Describe("[Tx Processing]", ginkgo.Serial, func() { for _, test := range testRegistry.List() { ginkgo.It(fmt.Sprintf("Custom VM Test '%s'", test.Name), func() { require.NoError(testNetwork.SynchronizeNetwork(context.Background())) - test.Fnc(ginkgo.GinkgoT(), testNetwork, test.AuthFactories...) + test.Fnc(ginkgo.GinkgoT(), testNetwork, test.AuthFactories) }) } } From ae81fde315f56d7c81637b24d4b810ebe8a05012 Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Wed, 27 Nov 2024 20:51:42 +0100 Subject: [PATCH 08/10] tests registry: add a decorator function to check the authFactories length --- tests/registry/registry.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/registry/registry.go b/tests/registry/registry.go index 88818065e9..b555d6c151 100644 --- a/tests/registry/registry.go +++ b/tests/registry/registry.go @@ -5,6 +5,7 @@ package registry import ( "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/require" "github.com/ava-labs/hypersdk/chain" "github.com/ava-labs/hypersdk/genesis" @@ -62,7 +63,7 @@ func (r *Registry) GenerateCustomAllocations(generateAuthFactory func() (chain.A var testRegistries = map[*Registry]bool{} func Register(registry *Registry, name string, f TestFunc, requestedBalances ...uint64) bool { - registry.Add(name, f, requestedBalances...) + registry.Add(name, withRequiredPrefundedAuthFactories(f, len(requestedBalances)), requestedBalances...) testRegistries[registry] = true return true } @@ -70,3 +71,11 @@ func Register(registry *Registry, name string, f TestFunc, requestedBalances ... func GetTestsRegistries() map[*Registry]bool { return testRegistries } + +// withRequiredPrefundedAuthFactories wraps the TestFunc in a new TestFunc adding length validation over the provided authFactories +func withRequiredPrefundedAuthFactories(f TestFunc, requiredLength int) TestFunc { + return func(t ginkgo.FullGinkgoTInterface, tn workload.TestNetwork, authFactories []chain.AuthFactory) { + require.Len(t, authFactories, requiredLength, "required pre-funded authFactories have not been initialized") + f(t, tn, authFactories) + } +} From 578ddedd4eda123d9296019f0e78fd684943cd04 Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Wed, 27 Nov 2024 21:47:34 +0100 Subject: [PATCH 09/10] tests: morpheus Transfer Transaction test use pre-funded authFactories --- examples/morpheusvm/tests/e2e/e2e_test.go | 4 +--- .../tests/integration/integration_test.go | 4 +--- examples/morpheusvm/tests/transfer.go | 23 +++++++++++-------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/examples/morpheusvm/tests/e2e/e2e_test.go b/examples/morpheusvm/tests/e2e/e2e_test.go index 8261a9c3e9..a392e81fe1 100644 --- a/examples/morpheusvm/tests/e2e/e2e_test.go +++ b/examples/morpheusvm/tests/e2e/e2e_test.go @@ -10,12 +10,10 @@ import ( "github.com/ava-labs/avalanchego/tests/fixture/e2e" "github.com/stretchr/testify/require" - "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" - _ "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" // include the tests that are shared between the integration and e2e - "github.com/ava-labs/hypersdk/abi" "github.com/ava-labs/hypersdk/auth" "github.com/ava-labs/hypersdk/examples/morpheusvm/consts" + "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" // include the tests that are shared between the integration and e2e "github.com/ava-labs/hypersdk/examples/morpheusvm/tests/workload" "github.com/ava-labs/hypersdk/examples/morpheusvm/throughput" "github.com/ava-labs/hypersdk/examples/morpheusvm/vm" diff --git a/examples/morpheusvm/tests/integration/integration_test.go b/examples/morpheusvm/tests/integration/integration_test.go index d00fdc7b11..71f891bbdd 100644 --- a/examples/morpheusvm/tests/integration/integration_test.go +++ b/examples/morpheusvm/tests/integration/integration_test.go @@ -8,11 +8,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" - _ "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" // include the tests that are shared between the integration and e2e - "github.com/ava-labs/hypersdk/auth" "github.com/ava-labs/hypersdk/crypto/ed25519" + "github.com/ava-labs/hypersdk/examples/morpheusvm/tests" // include the tests that are shared between the integration and e2e "github.com/ava-labs/hypersdk/examples/morpheusvm/tests/workload" "github.com/ava-labs/hypersdk/examples/morpheusvm/vm" "github.com/ava-labs/hypersdk/tests/integration" diff --git a/examples/morpheusvm/tests/transfer.go b/examples/morpheusvm/tests/transfer.go index 29e42694c4..2df64acfb2 100644 --- a/examples/morpheusvm/tests/transfer.go +++ b/examples/morpheusvm/tests/transfer.go @@ -27,19 +27,21 @@ var _ = registry.Register(TestsRegistry, "Transfer Transaction", func(t ginkgo.FullGinkgoTInterface, tn tworkload.TestNetwork, authFactories []chain.AuthFactory) { require := require.New(t) ctx := context.Background() - targetFactory := authFactories[0] - authFactory := tn.Configuration().AuthFactories()[0] + sourceAuthFactory, targetAuthFactory := authFactories[0], authFactories[1] client := jsonrpc.NewJSONRPCClient(tn.URIs()[0]) - balance, err := client.GetBalance(ctx, targetFactory.Address()) + sourceBalance, err := client.GetBalance(ctx, sourceAuthFactory.Address()) require.NoError(err) - require.Equal(uint64(1000), balance) + require.Equal(uint64(1000000), sourceBalance) + targetBalance, err := client.GetBalance(ctx, targetAuthFactory.Address()) + require.NoError(err) + require.Equal(uint64(1000000), targetBalance) tx, err := tn.GenerateTx(ctx, []chain.Action{&actions.Transfer{ - To: targetFactory.Address(), + To: targetAuthFactory.Address(), Value: 1, }}, - authFactory, + sourceAuthFactory, ) require.NoError(err) @@ -47,7 +49,10 @@ var _ = registry.Register(TestsRegistry, "Transfer Transaction", defer timeoutCtxFnc() require.NoError(tn.ConfirmTxs(timeoutCtx, []*chain.Transaction{tx})) - balance, err = client.GetBalance(ctx, targetFactory.Address()) + sourceBalance, err = client.GetBalance(ctx, sourceAuthFactory.Address()) + require.NoError(err) + require.True(uint64(1000000) > sourceBalance) + targetBalance, err = client.GetBalance(ctx, targetAuthFactory.Address()) require.NoError(err) - require.Equal(uint64(1001), balance) - }, 1000) + require.Equal(uint64(1000001), targetBalance) + }, 1000000, 1000000) From 9515e1a8e3c631fba7f18cd2d6516e8c4551fe74 Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Wed, 27 Nov 2024 21:58:38 +0100 Subject: [PATCH 10/10] doc: update testing morpheus Transfer Transaction --- docs/tutorials/morpheusvm/5_testing.md | 29 +++++++++++++++----------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/docs/tutorials/morpheusvm/5_testing.md b/docs/tutorials/morpheusvm/5_testing.md index ed659f0d4c..183b69b20e 100644 --- a/docs/tutorials/morpheusvm/5_testing.md +++ b/docs/tutorials/morpheusvm/5_testing.md @@ -355,7 +355,7 @@ import ( // ref https://onsi.github.io/ginkgo/#mental-model-how-ginkgo-traverses-the-spec-hierarchy var TestsRegistry = ®istry.Registry{} -var _ = registry.Register(TestsRegistry, "Transfer Transaction", func(t ginkgo.FullGinkgoTInterface, tn tworkload.TestNetwork) { +var _ = registry.Register(TestsRegistry, "Transfer Transaction", func(t ginkgo.FullGinkgoTInterface, tn tworkload.TestNetwork, authFactories []chain.AuthFactory) { }) ``` @@ -367,14 +367,14 @@ Afterwards, we have the following snippet: ```go registry.Register(TestsRegistry, "Transfer Transaction", func(t ginkgo.FullGinkgoTInterface, tn tworkload.TestNetwork, authFactories ...chain.AuthFactory) { -}, 1000) +}, 1000000, 1000000) ``` -Here, we are adding a test to `TestRegistry`, requesting an authFactory to be funded with 1000 tokens. However, we're +Here, we are adding a test to `TestRegistry`, requesting an authFactory to be funded with 1_000_000 tokens. However, we're missing the test itself. In short, here's what we want to do in our testing logic: -- Setup necessary values & Check the funds of the requested authFactory +- Setup necessary values & Check the funds of the requested authFactories - Create our test TX - Send our TX - Require that our TX is sent and that the outputs are as expected @@ -386,13 +386,15 @@ function: ```go require := require.New(t) ctx := context.Background() - targetFactory := authFactories[0] - authFactory := tn.Configuration().AuthFactories()[0] + sourceAuthFactory, targetAuthFactory := authFactories[0], authFactories[1] client := jsonrpc.NewJSONRPCClient(tn.URIs()[0]) - balance, err := client.GetBalance(ctx, targetFactory.Address()) + sourceBalance, err := client.GetBalance(ctx, sourceAuthFactory.Address()) require.NoError(err) - require.Equal(uint64(1000), balance) + require.Equal(uint64(1000000), sourceBalance) + targetBalance, err := client.GetBalance(ctx, targetAuthFactory.Address()) + require.NoError(err) + require.Equal(uint64(1000000), targetBalance) ``` Next, we'll create our test transaction. In short, we'll want to send a value of @@ -400,10 +402,10 @@ Next, we'll create our test transaction. In short, we'll want to send a value of ```go tx, err := tn.GenerateTx(context.Background(), []chain.Action{&actions.Transfer{ - To: toAddress, + To: targetAuthFactory.Address(, Value: 1, }}, - authFactory, + sourceAuthFactory, ) require.NoError(err) ``` @@ -425,9 +427,12 @@ the following: defer timeoutCtxFnc() require.NoError(tn.ConfirmTxs(timeoutCtx, []*chain.Transaction{tx})) - balance, err = client.GetBalance(context.Background(), targetFactory.Address()) + sourceBalance, err = client.GetBalance(ctx, sourceAuthFactory.Address()) + require.NoError(err) + require.True(uint64(1000000) > sourceBalance) + targetBalance, err = client.GetBalance(ctx, targetAuthFactory.Address()) require.NoError(err) - require.Equal(uint64(1001), balance) + require.Equal(uint64(1000001), targetBalance) ``` ## Registering our Tests