Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tmpnet] Enable bootstrap of subnets with disjoint validator sets #3138

Merged
merged 3 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 41 additions & 12 deletions tests/e2e/vms/xsvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/stretchr/testify/require"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/tests"
"github.com/ava-labs/avalanchego/tests/fixture/e2e"
"github.com/ava-labs/avalanchego/tests/fixture/subnet"
Expand All @@ -35,9 +36,17 @@ func XSVMSubnetsOrPanic(nodes ...*tmpnet.Node) []*tmpnet.Subnet {
if err != nil {
panic(err)
}
subnetANodes := nodes
subnetBNodes := nodes
if len(nodes) > 1 {
// Validate tmpnet bootstrap of a disjoint validator set
midpoint := len(nodes) / 2
subnetANodes = nodes[:midpoint]
subnetBNodes = nodes[midpoint:]
}
return []*tmpnet.Subnet{
subnet.NewXSVMOrPanic(subnetAName, key, nodes...),
subnet.NewXSVMOrPanic(subnetBName, key, nodes...),
subnet.NewXSVMOrPanic(subnetAName, key, subnetANodes...),
subnet.NewXSVMOrPanic(subnetBName, key, subnetBNodes...),
}
}

Expand All @@ -55,14 +64,21 @@ var _ = ginkgo.Describe("[XSVM]", func() {
sourceChain := sourceSubnet.Chains[0]
destinationChain := destinationSubnet.Chains[0]

apiNode := network.Nodes[0]
tests.Outf(" issuing transactions on %s (%s)\n", apiNode.NodeID, apiNode.URI)
sourceValidators := getNodesForIDs(network.Nodes, sourceSubnet.ValidatorIDs)
require.NotEmpty(sourceValidators)
sourceAPINode := sourceValidators[0]
tests.Outf(" issuing transactions for source subnet on %s (%s)\n", sourceAPINode.NodeID, sourceAPINode.URI)

destinationValidators := getNodesForIDs(network.Nodes, destinationSubnet.ValidatorIDs)
require.NotEmpty(destinationValidators)
destinationAPINode := destinationValidators[0]
tests.Outf(" issuing transactions for destination subnet on %s (%s)\n", destinationAPINode.NodeID, destinationAPINode.URI)

destinationKey, err := secp256k1.NewPrivateKey()
require.NoError(err)

ginkgo.By("checking that the funded key has sufficient funds for the export")
sourceClient := api.NewClient(apiNode.URI, sourceChain.ChainID.String())
sourceClient := api.NewClient(sourceAPINode.URI, sourceChain.ChainID.String())
initialSourcedBalance, err := sourceClient.Balance(
e2e.DefaultContext(),
sourceChain.PreFundedKey.Address(),
Expand All @@ -75,7 +91,7 @@ var _ = ginkgo.Describe("[XSVM]", func() {
exportTxStatus, err := export.Export(
e2e.DefaultContext(),
&export.Config{
URI: apiNode.URI,
URI: sourceAPINode.URI,
SourceChainID: sourceChain.ChainID,
DestinationChainID: destinationChain.ChainID,
Amount: units.Schmeckle,
Expand All @@ -87,7 +103,7 @@ var _ = ginkgo.Describe("[XSVM]", func() {
tests.Outf(" issued transaction with ID: %s\n", exportTxStatus.TxID)

ginkgo.By("checking that the export transaction has been accepted on all nodes")
for _, node := range network.Nodes[1:] {
for _, node := range sourceValidators[1:] {
require.NoError(api.AwaitTxAccepted(
e2e.DefaultContext(),
api.NewClient(node.URI, sourceChain.ChainID.String()),
Expand All @@ -104,7 +120,7 @@ var _ = ginkgo.Describe("[XSVM]", func() {
transferTxStatus, err := transfer.Transfer(
e2e.DefaultContext(),
&transfer.Config{
URI: apiNode.URI,
URI: destinationAPINode.URI,
ChainID: destinationChain.ChainID,
AssetID: destinationChain.ChainID,
Amount: units.Schmeckle,
Expand All @@ -116,14 +132,14 @@ var _ = ginkgo.Describe("[XSVM]", func() {
tests.Outf(" issued transaction with ID: %s\n", transferTxStatus.TxID)

ginkgo.By(fmt.Sprintf("importing to blockchain %s on subnet %s", destinationChain.ChainID, destinationSubnet.SubnetID))
sourceURIs := make([]string, len(network.Nodes))
for i, node := range network.Nodes {
sourceURIs := make([]string, len(sourceValidators))
for i, node := range sourceValidators {
sourceURIs[i] = node.URI
}
importTxStatus, err := importtx.Import(
e2e.DefaultContext(),
&importtx.Config{
URI: apiNode.URI,
URI: destinationAPINode.URI,
SourceURIs: sourceURIs,
SourceChainID: sourceChain.ChainID.String(),
DestinationChainID: destinationChain.ChainID.String(),
Expand All @@ -140,9 +156,22 @@ var _ = ginkgo.Describe("[XSVM]", func() {
require.GreaterOrEqual(initialSourcedBalance-units.Schmeckle, sourceBalance)

ginkgo.By("checking that the balance of the destination key is non-zero")
destinationClient := api.NewClient(apiNode.URI, destinationChain.ChainID.String())
destinationClient := api.NewClient(destinationAPINode.URI, destinationChain.ChainID.String())
destinationBalance, err := destinationClient.Balance(e2e.DefaultContext(), destinationKey.Address(), sourceChain.ChainID)
require.NoError(err)
require.Equal(units.Schmeckle, destinationBalance)
})
})

// Retrieve the nodes corresponding to the provided IDs
func getNodesForIDs(nodes []*tmpnet.Node, nodeIDs []ids.NodeID) []*tmpnet.Node {
desiredNodes := make([]*tmpnet.Node, 0, len(nodeIDs))
for _, node := range nodes {
for _, nodeID := range nodeIDs {
if node.NodeID == nodeID {
desiredNodes = append(desiredNodes, node)
}
}
}
return desiredNodes
}
6 changes: 3 additions & 3 deletions tests/fixture/tmpnet/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ func (n *Network) Bootstrap(ctx context.Context, w io.Writer) error {
}

// Don't restart the node during subnet creation since it will always be restarted afterwards.
if err := n.CreateSubnets(ctx, w, false /* restartRequired */); err != nil {
if err := n.CreateSubnets(ctx, w, bootstrapNode.URI, false /* restartRequired */); err != nil {
return err
}

Expand Down Expand Up @@ -646,7 +646,7 @@ func (n *Network) GetSubnet(name string) *Subnet {

// Ensure that each subnet on the network is created. If restartRequired is false, node restart
// to pick up configuration changes becomes the responsibility of the caller.
func (n *Network) CreateSubnets(ctx context.Context, w io.Writer, restartRequired bool) error {
func (n *Network) CreateSubnets(ctx context.Context, w io.Writer, apiURI string, restartRequired bool) error {
createdSubnets := make([]*Subnet, 0, len(n.Subnets))
for _, subnet := range n.Subnets {
if len(subnet.ValidatorIDs) == 0 {
Expand Down Expand Up @@ -748,7 +748,7 @@ func (n *Network) CreateSubnets(ctx context.Context, w io.Writer, restartRequire
validatorNodes = append(validatorNodes, node)
}

if err := subnet.AddValidators(ctx, w, validatorNodes...); err != nil {
if err := subnet.AddValidators(ctx, w, apiURI, validatorNodes...); err != nil {
return err
}
}
Expand Down
4 changes: 1 addition & 3 deletions tests/fixture/tmpnet/subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,7 @@ func (s *Subnet) CreateChains(ctx context.Context, w io.Writer, uri string) erro
}

// Add validators to the subnet
func (s *Subnet) AddValidators(ctx context.Context, w io.Writer, nodes ...*Node) error {
apiURI := nodes[0].URI

func (s *Subnet) AddValidators(ctx context.Context, w io.Writer, apiURI string, nodes ...*Node) error {
wallet, err := s.GetWallet(ctx, apiURI)
if err != nil {
return err
Expand Down
Loading