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

Cosmos x/vstream implementation #5466

Closed
wants to merge 12 commits into from
Closed

Cosmos x/vstream implementation #5466

wants to merge 12 commits into from

Conversation

michaelfig
Copy link
Member

@michaelfig michaelfig commented May 30, 2022

refs: #5487

Description

On-chain stream publishing for the client described in @agoric/streams. See the x/vstream spec

Security Considerations

Documentation Considerations

Testing Considerations

@michaelfig michaelfig self-assigned this May 30, 2022
@michaelfig michaelfig mentioned this pull request May 30, 2022
@michaelfig michaelfig requested a review from JimLarson May 30, 2022 03:22
@michaelfig michaelfig marked this pull request as draft May 30, 2022 03:22
@michaelfig michaelfig force-pushed the mfig-vstream branch 4 times, most recently from 27e7cc4 to 1f47045 Compare May 30, 2022 23:21
Base automatically changed from mfig-chain-storage-revamp to master June 5, 2022 05:09
Copy link
Contributor

@JimLarson JimLarson left a comment

Choose a reason for hiding this comment

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

Preview of comments. More to come, hopefully this weekend.

];

// The subkey under which the cell is stored.
bytes store_subkey = 3 [
Copy link
Contributor

Choose a reason for hiding this comment

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

This is the subkey/child key for vstorage? Make that explicit, and be consistent with the choice of "sub" vs "child" made for vstorage.

Copy link
Member Author

Choose a reason for hiding this comment

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

No, this is at a lower level than vstorage: the Cosmos SDK multistore. I've noted as such.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, "subkey" doesn't appear to be standard cosmos terminology - the APIs just use "key".

golang/cosmos/proto/agoric/types/stream.proto Outdated Show resolved Hide resolved
(gogoproto.moretags) = "yaml:\"end_state\""
];

// The prior position in the stream.
Copy link
Contributor

Choose a reason for hiding this comment

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

Add If this is the first cell in the stream, this will be the default value. All other cells will have a reference with a nonzero block height.

];

// The sequence number of the value at this position.
uint64 sequence_number = 4 [
Copy link
Contributor

Choose a reason for hiding this comment

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

I first thought this was redundant with firstSequenceNumber in StreamCell, but now I see this is necessary for a reference to a fork point within a cell.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see you've removed firstSequenceNumber from StreamCell. I guess it's redundant as long as you're always accessing a cell via a StreamPosition, but it seems a little too bold to leave this essential information only extrinsic. Consider restoring the field.

agoric "github.com/Agoric/agoric-sdk/golang/cosmos/types"
)

func NewStreamCell(blockHeight int64, seq uint64) StreamCell {
Copy link
Contributor

Choose a reason for hiding this comment

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

Document that seq is the first sequence number to use in the cell.

Copy link
Member Author

Choose a reason for hiding this comment

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

I changed this to take a prior position. It's better not to leak the sequence number abstraction.

];
}

// StreamPosition is data that refers to a particular stream cell value.
Copy link
Contributor

Choose a reason for hiding this comment

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

Add The default value of this message is the equivalent of a null pointer.

priorCell.UpdatedBlockHeight,
state.StoreName(),
state.StoreSubkey(),
uint64(len(priorCell.Values)),
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't you need to add priorCell.FirstSequenceNumber? Add a test which would have caught this.

Copy link
Member Author

Choose a reason for hiding this comment

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

Turns out that was redundant information that I've removed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not fixed yet.

golang/cosmos/types/stream/cell.go Show resolved Hide resolved

func GetLatestPosition(ctx sdk.Context, state agoric.StateRef) (*StreamPosition, error) {
var priorCell StreamCell
if state.Exists(ctx) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider testing for !state.Exists(ctx) and returning NewZeroStreamPosition(). It looks like a non-existing cell results in the return of a zero stream position, but I think it's safer to make this explicit rather than relying on undocumented, implicit behavior.

sdk "github.com/cosmos/cosmos-sdk/types"
)

// An interface to allow updating KVStore-backed state and extracting proof
Copy link
Contributor

Choose a reason for hiding this comment

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

An interface ... to a stored StreamCell.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not StreamCell specific.

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, but see below for comments that make it explicit when we are expecting it to reference a StreamCell. When do you think the SDK might start using generics?

type StateRef[T Jsoner] interface {
    Read(ctx sdk.Context) (T, error)
    Write(ctx sdkContext, value T) error
    ...
}

Copy link
Contributor

@JimLarson JimLarson left a comment

Choose a reason for hiding this comment

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

Here's my final comments on the code. I'll address the spec documents in another PR - probably after I've seen more of how this all will be used.

// If state=END_STATE_FAILURE, the last value is the serialised error.
repeated bytes values = 1;

// The block height in which this cell was last updated.
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm. In the comment at least, instead of "was last updated", try "was produced", and see if that inspires a different name.

];

// The subkey under which the cell is stored.
bytes store_subkey = 3 [
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, "subkey" doesn't appear to be standard cosmos terminology - the APIs just use "key".

];

// The sequence number of the value at this position.
uint64 sequence_number = 4 [
Copy link
Contributor

Choose a reason for hiding this comment

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

I see you've removed firstSequenceNumber from StreamCell. I guess it's redundant as long as you're always accessing a cell via a StreamPosition, but it seems a little too bold to leave this essential information only extrinsic. Consider restoring the field.

)

// NewStreamCell creates a new StreamCell at blockHeight with the specified
// prior position.
Copy link
Contributor

Choose a reason for hiding this comment

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

Use a zero stream position if this is the first cell in the stream.

}

// GetLatestPosition returns the position of the last value in the cell, or a
// zero stream position if the referenced cell does not exist.
Copy link
Contributor

Choose a reason for hiding this comment

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

Since a StateRef could reference anything, document that it is expected to reference a StreamCell.

Add a note that it will unconditionally return the position of the last value in the cell regardless of the cell's end state. The cell end state should be checked to ensure the position is meaningful, e.g. not END_STATE_FAILURE.


option go_package = "github.com/Agoric/agoric-sdk/golang/cosmos/types/stream";

// StreamCell represents one publish state in a vstream stream.
Copy link
Contributor

Choose a reason for hiding this comment

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

"published". Consider instead "StreamCell contains the stream values that are published during the execution of a single block. Each StreamCell contains a reference to the prior cell in the stream.

import "gogoproto/gogo.proto";

option go_package = "github.com/Agoric/agoric-sdk/golang/cosmos/types/stream";

Copy link
Contributor

Choose a reason for hiding this comment

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

Introductory comment: "A stream is a sequence of arbitrary bytes values used by publishers to communicate with consumers. Values in a stream are indexed by 1-based contiguous sequence numbers. A stream is stored as a sequence of StreamCells. StreamCells are typically written to the same key in a KVStore, relying on reading at old block heights to see older values."

sdk "github.com/cosmos/cosmos-sdk/types"
)

// An interface to allow updating KVStore-backed state and extracting proof
Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, but see below for comments that make it explicit when we are expecting it to reference a StreamCell. When do you think the SDK might start using generics?

type StateRef[T Jsoner] interface {
    Read(ctx sdk.Context) (T, error)
    Write(ctx sdkContext, value T) error
    ...
}


var _ StateRef = KVStoreStateRef{}

func NewKVStoreStateRef(storeKey sdk.StoreKey, subkey []byte) *KVStoreStateRef {
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider not pointer-izing.

var _, _ StreamCellUpdater = AppendStreamCellUpdater{}, FailStreamCellUpdater{}

type StreamOperation struct {
state agoric.StateRef
Copy link
Contributor

Choose a reason for hiding this comment

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

Document that state is expected to reference a StreamCell.

@michaelfig
Copy link
Member Author

@gibson042 did a great job of implementing this feature mostly in JS with a light touch in Go, so this PR is superseded. Closing.

@michaelfig michaelfig closed this Jan 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants