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

[v2] Read blob version params from chain #922

Merged
merged 1 commit into from
Nov 22, 2024

Conversation

ian-shim
Copy link
Contributor

Why are these changes needed?

Remove hardcoded blob version params map, and read the values from chain.

Checks

  • I've made sure the tests are passing. Note that there might be a few flaky tests, in that case, please comment that they are not relevant.
  • I've checked the new test coverage and the coverage percentage didn't drop.
  • Testing Strategy
    • Unit tests
    • Integration tests
    • This PR is not tested :(

@ian-shim
Copy link
Contributor Author

ian-shim commented Nov 21, 2024

Depends on #921

@ian-shim ian-shim force-pushed the blob-version-params branch 4 times, most recently from b9796f9 to 132150e Compare November 21, 2024 06:03
@ian-shim ian-shim marked this pull request as ready for review November 21, 2024 06:13
@ian-shim ian-shim force-pushed the blob-version-params branch 2 times, most recently from 6b0eba4 to a888892 Compare November 21, 2024 21:05
@ian-shim ian-shim requested a review from jianoaix November 21, 2024 21:06
@@ -0,0 +1,26 @@
package common

type ReadOnlyMap[K comparable, V any] struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

ah I'd wish golang has const which will make it self-explain and enforced

node/node.go Outdated

// BlobVersionParams is a map of blob version parameters loaded from the chain.
// It is used to determine blob parameters based on the version number.
BlobVersionParams *corev2.BlobVersionParameterMap
Copy link
Contributor

Choose a reason for hiding this comment

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

This needs mutex protection for concurrent read/write

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 underlying map is read only and this pointer to the read only map gets swapped out atomically occasionally. Do we need synchronization here?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it needs to, this pointer (the address itself) may be undefined if it's not synchronized among threads (not sure how it's atomic swap if no mutex)

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 think you're right. Converted these into atomic.Pointer

node/node_v2.go Outdated
@@ -61,7 +65,11 @@ func (n *Node) DownloadBundles(ctx context.Context, batch *corev2.Batch, operato
relayIndex := rand.Intn(len(cert.RelayKeys))
relayKey := cert.RelayKeys[relayIndex]
for _, quorum := range cert.BlobHeader.QuorumNumbers {
assgn, err := corev2.GetAssignment(operatorState, batch.BlobCertificates[0].BlobHeader.BlobVersion, quorum, n.Config.ID)
blobParams, ok := n.BlobVersionParams.Get(cert.BlobHeader.BlobVersion)
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks when there is a new version upgrade, it may have an outage since different dispersers/nodes up to the different versions (and potentially cannot reach quorum threshold)?

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. The blob version needs to be registered onchain well before new blobs start using the new version.

Copy link
Contributor

Choose a reason for hiding this comment

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

So it's like: 1) add new version of params to smart contracts; 2) let sufficient num of operators upgrade; 3) let disperser(s) upgrade ?

Copy link
Contributor Author

@ian-shim ian-shim Nov 22, 2024

Choose a reason for hiding this comment

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

  1. Add new blob version onchain (multisig transaction)
  2. Wait for OnchainStateRefreshInterval (practically, wait for a lot more than this duration). If operator nodes, use the default value (1h), all parts of system will be aware of the new version within this time
  3. Let disperser & relay be aware of the blob version
  4. Blob with new version can be dispersed

@ian-shim ian-shim force-pushed the blob-version-params branch from a888892 to 385f7c2 Compare November 22, 2024 00:44
@@ -224,6 +224,13 @@ var (
Required: false,
EnvVar: common.PrefixEnvVar(EnvVarPrefix, "ENABLE_V2"),
}
OnchainStateRefreshIntervalFlag = cli.DurationFlag{
Copy link
Contributor

Choose a reason for hiding this comment

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

This may have an issue about having a single control for all onchain state refresh. It's possible we need to refresh different states (e.g. blob's store duration), and maybe at different intervals. Shall we just call this BlobParamsRefreshInterval?

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 going to have this control onchain state that changes very infrequently, for now such as relay addresses.
Maybe we can keep this name, and if we need to add other state that needs to be refreshed at different rate, we can add separate controls for those?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This reminds me that blob store duration isn't getting refreshed at all. It only gets read on bootup. Probably fine as they don't really change, but should we refresh those as part of this loop?

Copy link
Contributor

Choose a reason for hiding this comment

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

They also change very infrequently, maybe at similar level as blob params. SG to include them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will include them in a follow up PR

Copy link
Contributor

@anupsv anupsv left a comment

Choose a reason for hiding this comment

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

few small comments

}

ops, ok := state.Operators[quorum]
if !ok {
return nil, fmt.Errorf("no operators found for quorum %d", quorum)
}

if len(ops) > int(params.MaxNumOperators()) {
return nil, fmt.Errorf("too many operators for blob version %d", blobVersion)
if len(ops) > int(blobParams.MaxNumOperators) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use uint32 ?

}

numOperators := big.NewInt(int64(len(ops)))
numChunks := big.NewInt(int64(params.NumChunks))
numChunks := big.NewInt(int64(blobParams.NumChunks))
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use uint64?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is to convert uint64 to bigint. Do you mean use uint64 to represent numChunks instead of bigint?

@@ -58,9 +56,9 @@ func GetAssignments(state *core.OperatorState, blobVersion BlobVersion, quorum u
mp += int(a.chunks)
}

delta := int(params.NumChunks) - mp
delta := int(blobParams.NumChunks) - mp
Copy link
Contributor

Choose a reason for hiding this comment

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

Same, using uint instead of int.

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 think it should be int. Otherwise, delta can underflow if mp > numChunks

}
chunks, assignment, err := v.validateBlobQuorum(quorum, blob, blobParams, state)
if errors.Is(err, ErrBlobQuorumSkip) {
continue
Copy link
Contributor

Choose a reason for hiding this comment

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

worth adding a log here?

validVersions := make([]int32, 0, len(s.onchainState.BlobVersionParameters))
for version := range s.onchainState.BlobVersionParameters {
if _, ok := onchainState.BlobVersionParameters.Get(corev2.BlobVersion(blobHeaderProto.GetVersion())); !ok {
validVersions := make([]int32, 0, onchainState.BlobVersionParameters.Len())
Copy link
Contributor

Choose a reason for hiding this comment

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

can we use uint32's?

@ian-shim ian-shim force-pushed the blob-version-params branch from 385f7c2 to b678db5 Compare November 22, 2024 17:24
@ian-shim ian-shim merged commit b0f3288 into Layr-Labs:master Nov 22, 2024
6 checks passed
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.

3 participants