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

dsmr: replace hard coded validators with ChainState #1894

Merged
merged 50 commits into from
Feb 3, 2025

Conversation

tsachiherman
Copy link
Contributor

@tsachiherman tsachiherman commented Jan 27, 2025

What ?

This PR replaces the hard coded validators list and few more parameters that were previously hard-coded into the node with a dynamic ChainState interface.

The node test is currently have an implementation for that interface, which is used during testing.

Node creation

The node constructor which used to look like this:

func New[T Tx](
	log logging.Logger,
	nodeID ids.NodeID,
	networkID uint32,
	chainID ids.ID,
	pk *bls.PublicKey,
	signer warp.Signer,
	chunkStorage *ChunkStorage[T],
	getChunkClient *p2p.Client,
	getChunkSignatureClient *p2p.Client,
	chunkCertificateGossipClient *p2p.Client,
	validators []Validator, // TODO remove hard-coded validator set
	lastAccepted Block,
	quorumNum uint64,
	quorumDen uint64,
	timeValidityWindow TimeValidityWindow[*emapChunkCertificate],
	validityWindowDuration time.Duration,
)

looks now like that:

func New[T Tx](
	log logging.Logger,
	nodeID ids.NodeID,
	chainState ChainState,
	pk *bls.PublicKey,
	signer warp.Signer,
	chunkStorage *ChunkStorage[T],
	getChunkClient *p2p.Client,
	getChunkSignatureClient *p2p.Client,
	chunkCertificateGossipClient *p2p.Client,
	lastAccepted Block,
	timeValidityWindow TimeValidityWindow[*emapChunkCertificate],
	validityWindowDuration time.Duration,
)

and the ChainState is defined as :

type ChainState interface {
	GetNetworkParams() (networdID uint32, subnetID, chainID ids.ID)
	GetSignatureParams(ctx context.Context) (validators warp.CanonicalValidatorSet, quorumNum uint64, quorumDen uint64, err error)
	GetValidatorSet(ctx context.Context) (map[ids.NodeID]*snowValidators.GetValidatorOutput, error)
}

…va-labs/hypersdk into tsachi/configurable-chunk-rate-limiter
…ava-labs/hypersdk into tsachi/configurable-chunk-rate-limiter2
…ava-labs/hypersdk into tsachi/configurable-chunk-rate-limiter2
@tsachiherman tsachiherman changed the title wip : chainstate dsmr: replace hard coded validators with ChainState Jan 29, 2025
@tsachiherman tsachiherman marked this pull request as ready for review January 29, 2025 19:59
@tsachiherman tsachiherman self-assigned this Jan 29, 2025
tests/e2e/e2e.go Outdated
Comment on lines 185 to 186
// Tsachi : The following line was commented out, as it's no longer supported by avalanchego.
// require.NoError(syncNode.SaveAPIPort())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we remove this comment as it's not relevant after this change?

For comments like this, could we make them on the diff in the PR as opposed to putting them in the code itself where they will go out of date once they're merged?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove the TODO above this as well since it was documenting that we should be able to get rid of this call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to figure out if this is no longer needed. Can you take a look https://github.com/ava-labs/avalanchego/pull/3650/files and let me know what you think ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm it looks like with the new behavior the URI to access the node may change, so this does not look correct to me.

In the test above, we have saved the syncNodeURI and added it to uris, which we use throughout the tests below, so if that URI is not guaranteed to be reachable after the restart we may fail.

If AvalancheGo deprecated support for this feature, then we'll need to make sure to either switch away from saving them to uris and syncNodeURI and creating them on demand from the updated node instance or update those variables in place after the restart.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

x/dsmr/node.go Outdated
Comment on lines 52 to 56
type ChainState interface {
GetNetworkParams() (networdID uint32, subnetID, chainID ids.ID)
GetSignatureParams(ctx context.Context) (validators warp.CanonicalValidatorSet, quorumNum uint64, quorumDen uint64, err error)
GetLatestValidatorSet(ctx context.Context) (map[ids.NodeID]*snowValidators.GetValidatorOutput, error)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we break this into individual accessors rather than grouping them based on what we will need at different points? This way when we need networkID and chainID, we can access those two rather than grouping all the network params defined by this function together.

In the future, we may want to make the rules configurable based on the block timestamp and fetch the validator set based off of the P-Chain height (both fine to leave as is for now). WIP for adding ProposerVM block context into the block is here: #1897.

For now, can we break this up to fetch the immutable params individually ie. networkID, subnetID, chainID, quorumNum, and quorumDenom. Can we also switch to two functions to fetch the canonical validator set and check whether a specific nodeID is a validator (can add P-Chain height as a parameter in the future)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -3,8 +3,8 @@ module github.com/ava-labs/hypersdk/examples/morpheusvm
go 1.22.8

require (
github.com/ava-labs/avalanchego v1.11.13-0.20241230212828-6dea1b366756
github.com/ava-labs/hypersdk v0.0.1
github.com/ava-labs/avalanchego v1.12.3-warp-verify5.0.20250129181352-a1aff06d0fef
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have to update avalanchego to use the new localsigner? I think we can replace the usage of the hard-coded validator set w/out a version upgrade

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not about the upgrade to localsigner. The goal here was to be able to verify the signature c.Signature.Verify without providing it with pseudo interface. ( i.e. provide it with the data it truly needs to consume ). see ava-labs/avalanchego#3679 for more details.

x/dsmr/node.go Outdated
Comment on lines 53 to 54
GetNetworkParams() (networdID uint32, subnetID, chainID ids.ID)
GetSignatureParams(ctx context.Context) (validators warp.CanonicalValidatorSet, quorumNum uint64, quorumDen uint64, err error)
Copy link
Contributor

@joshua-kim joshua-kim Jan 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we making this a part of this interface? If it's to support forking live networks I think this is a premature abstraction and as a tradeoff it bloats this interface (and if we wanted to support that I think this interface would need some time parameter/block height parameter to support that). IMO this interface should just return validator sets.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it's meant to support live networks. I believe that @aaronbuchwald has some additions he plans to add on top of that.

Copy link
Contributor

@joshua-kim joshua-kim Jan 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to support forking live networks I think we need some timestamp/block height parameter in this interface then

}

func (*testChainState) GetNetworkParams() (uint32, ids.ID, ids.ID) {
return networkID /*subnetID*/, ids.Empty, chainID
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: don't leave these comments

ctx,
pChain,
0,
ids.Empty, /*subnetID*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same nit here

return networkID /*subnetID*/, ids.Empty, chainID
}

func (t *testChainState) getValidatorSet() map[ids.NodeID]*validators.GetValidatorOutput {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this introduces complexity, can we just cache this in the testChainState struct instead of having to re-call this function every time you want to get the validator set

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method is being used only in a single place ( within GetCanonicalValidatorSet ), and exclusively used for testing purposes. It doesn't seems that we would gain much by caching the map here. We could use a map as the backing storage ( instead of a slice ).

Comment on lines 1558 to 1571
pChain := &validatorstest.State{
GetSubnetIDF: func(context.Context, ids.ID) (ids.ID, error) {
return t.GetSubnetID(), nil
},
GetValidatorSetF: func(
context.Context,
uint64,
ids.ID,
) (map[ids.NodeID]*validators.GetValidatorOutput, error) {
return t.getValidatorSet(), nil
},
}

canonicalValidators, err := warp.GetCanonicalValidatorSetFromSubnetID(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we need this, can we include it in the testChainState type rather than constructing it on demand in this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure. it would require a constructor, but no prob.

x/dsmr/node.go Outdated
@@ -157,15 +152,16 @@ func (n *Node[T]) BuildChunk(
return ErrEmptyChunk
}

networkID, chainID := n.chainState.GetNetworkID(), n.chainState.GetChainID()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we break this into two separate lines?

Comment on lines 1566 to 1575
canonicalValidators, err := warp.GetCanonicalValidatorSetFromSubnetID(
ctx,
t,
0,
ids.Empty,
)
if err != nil {
return warp.CanonicalValidatorSet{}, err
}
return canonicalValidators, err
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be a single line?

quorumDen uint64
}

func newTestChainState(validatorsSlice []Validator, quorumNum, quorumDen uint64) *testChainState { //nolint:unparam
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This nolint label should not be necessary since each of the parameters is used, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the test, we only use (1,1) for the quorum params. Its ok, since we don't really want to test that, but the linter alert anyway.

@aaronbuchwald aaronbuchwald merged commit 9b7e1ef into main Feb 3, 2025
17 checks passed
@aaronbuchwald aaronbuchwald deleted the tsachi/chainstate branch February 3, 2025 20:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants