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

TEST-9: added OnChanOpenAck account host chain setup (some sub-parts blocked by new tickets) #13

Closed
wants to merge 6 commits into from

Conversation

riley-stride
Copy link
Contributor

@riley-stride riley-stride commented May 16, 2022

High level summary: the first time a channel is opened to any hostZone, OnChanOpenAck will run. We add logic here to populate the HostZone store with host chain accounts. There’s one channel per account on the HostZone, so switch on portID to determine which is being opened and store the appropriate account.

See TEST-9 in Jira

Note: this PR included the addition of the third_party folder which includes several imports. We can remove it from here and add it to a separate PR if that's cleaner.

@asalzmann
Copy link
Contributor

Can you add a high level summary here?

@riley-stride
Copy link
Contributor Author

Can you add a high level summary here?

@asalzmann added

@riley-stride
Copy link
Contributor Author

This should be a cleaner commit now that third_party was moved to TEST-47 👍

Copy link
Contributor

@asalzmann asalzmann left a comment

Choose a reason for hiding this comment

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

Exciting to see this coming together! I left some comments throughout, overall the approach makes sense to me. The only major comments are

  • We'll need to align on a portId schema (as well as how we map between portIds and associated fields like ICAAccount type)
  • Whether the funcionality that's in OnChanOpenAck here should go in OnChanOpenConfirm

My understanding of the stages of opening channels is

  1. OnChanOpenInit - A lets B know that it wants to open a channel
  2. OnChanOpenTry - B tries to open the channel
  3. OnChanOpenAck - A lets B know if the channel is open
  4. OnChanOpenConfirm - if it's open, B lets A know that it also has the channel open

Not clear to me whether B could fail in step 4 and whether we should do cleanup logic if that's the case.

Before merging this, can we test this by creating a connection between two chains and checking the HostZone store?

@@ -19,3 +19,8 @@ message GenesisState {
uint64 hostZoneCount = 6;
// this line is used by starport scaffolding # genesis/proto/state
}

message PortConnectionTuple {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need this tuple?

repeated Validator blacklistedValidators = 4;
repeated ICAAccount rewardsAccount = 5;
repeated ICAAccount feeAccount = 6;
repeated ICAAccount delegationAccounts = 4;
Copy link
Contributor

@asalzmann asalzmann May 18, 2022

Choose a reason for hiding this comment

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

Reusing proto fields (the numbers next to each field) is bad practice and can break databases, because of the way protos are serialized / deserialized. The proto field number indicates where in the serialized byte-string the data is stored, so if you change the field number database may no longer work. For example, if a proto message has a field string animal = 2 and you store a string "dog" at a specific position in the serialized byte-string (via a db write), then change the proto field to int animal = 2, the next time you read that field the proto will deserialize the byte-string and try to interpret the bytes representing "dog" as an int.

Instead, use the "reserved" syntax to deprecate fields like so

reserved 4, 5, 6;

and set the new field to the next id (7 in this case) like so

repeated ICAAccount delegationAccounts = 7;

docs: https://developers.google.com/protocol-buffers/docs/proto3#assigning_field_numbers

Copy link
Contributor

Choose a reason for hiding this comment

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

How are you thinking about removing the fee and rewards accounts? I think we still need these, if we remove them I'm not sure where we'll send fees + rewards.

Copy link
Contributor

Choose a reason for hiding this comment

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

In #12 I made all of the ICAAccount fields not repeated (with the exception of delegationAccounts). I think it will simplify the code somewhat to have a single account handling fees, rewards, etc. on each HostChain, but we do lose a little bit of flexibility. How do you think we should handle these?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fee account: I believe we need the fee account (just an addr on host chain that collects revenue from protocol, NOT an ICA acct). I added that back in on another PR. I

Rewards account: I don't think we need this because we can just sweep rewards to the deposit or delegation account and the regular epoch logic will delegate these claimed rewards from either of those accounts.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for pointing out the proto field numbring issue. Let me make sure I understand: you're suggesting that there are some web2 cases (e.g. some DBs) that break if you change the type of a particular field. It's less clear to me that we need to deprecate proto fields here given we re-compile every time. Maybe we will need to once the chain is running, so we should just follow that convention now?

Copy link
Contributor

@asalzmann asalzmann May 19, 2022

Choose a reason for hiding this comment

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

It's not specific to DBs, it's specific to protos - whenever you read a proto byte-string into memory (doesn't matter where the byte-string comes from, it could be a DB, a blockchain, a csv, etc.) the only way the code can interpret that byte-string is through the current message definition, so if it was defined using an old message schema it could throw an error. Deprecating fields is fine (e.g. removing a field from the proto entirely), the byte-string will still be interpreted correctly and when it's read into memory the deprecated data in the byte-string will be ignored, but replacing fields and using the same id is error-prone (case outlined above).

It's true that technically this doesn't break anything while we're in the development pattern of restarting chain state (we clear out the "DB" every time we re-initialize the chain), but defining new field ids is cheap and forgetting this later / having to think about when we need to define new fields is expensive and error-prone, so would bias towards following the convention now regardless.

Copy link
Contributor

Choose a reason for hiding this comment

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

Re: the rewards account, sweeping rewards into the deposit account could be a bit complex - I think we'd need an IBC transaction (deposit account is on stride, rewards accrue on host), although we could sweep them directly into the delegation account. As long as we only have a single delegation account, I think this works fine, if we have multiple delegation accounts it could be more complex (we'd have to withdraw rewards in chunks to different delegation accounts)

)

type (
Keeper struct {
// *cosmosibckeeper.Keeper
cdc codec.BinaryCodec
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 we have different linters, we should all get in sync on using one (not important for this PR, just making a note)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, I'm using this one https://github.com/golang/vscode-go/blob/master/docs/features.md#lint-errors. Lmk if you have one you prefer

@@ -78,3 +80,40 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
func (k *Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error {
return k.scopedKeeper.ClaimCapability(ctx, cap, name)
}

func (k *Keeper) SetConnectionForPort(ctx sdk.Context, connectionId string, port string) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

This code is a bit confusing to me, should there be a single connection between any two HostZones? Rather than storing a connection for each port, could we derive the HostZone some other way? I think this works for ICAAccounts (which have a unique port per ICA), but I would think other types of ports could support multiple connections? E.g. I would guess that the transfer port on Osmosis is connected to every zone that Osmosis is connected to

@@ -0,0 +1,43 @@
package keeper
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need a new keeper file here? Wondering if these functions go in stride/x/stakeibc/keeper/host_zone.go

zoneInfo.DelegationAccounts = append(zoneInfo.DelegationAccounts, delegationAccount)
case portParts[1] == "feeAccount":
// set HostZone feeAccount
// TODO (TEST-) add Fee account safety checks (we can't have this changing without rigorous validation)
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing ticket number?

Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need an ICAAccount here? Something like feeAccount = &types.ICAAccount{Address: address, Balance: 0, DelegatedBalance: 0, Delegations: []*types.Delegation{}}

const (
HostZoneKey = "HostZone-value-"
HostZoneCountKey = "HostZone-count-"
prefixZone = iota + 1
Copy link
Contributor

Choose a reason for hiding this comment

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

@vish-stride brought up that this syntax looks off, I think this will just set all of the fields to 1? (iota is another way to represent 0 iirc)

var (
// PortKey defines the key to store the port ID in store
PortKey = KeyPrefix("stakeibc-port-")
PortKey = KeyPrefix("stakeibc-port-")
Copy link
Contributor

Choose a reason for hiding this comment

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

What are these prefixes being used for?

PortKey = KeyPrefix("stakeibc-port-")
PortKey = KeyPrefix("stakeibc-port-")
KeyPrefixZone = []byte{prefixZone}
KeyPrefixIntent = []byte{prefixIntent}
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need this (don't have intents)

KeyPrefixIntent = []byte{prefixIntent}
KeyPrefixPortMapping = []byte{prefixPortMapping}
KeyPrefixReceipt = []byte{prefixReceipt}
KeyPrefixWithdrawalRecord = []byte{prefixWithdrawalRecord}
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we tracking withdrawal records?

@riley-stride
Copy link
Contributor Author

This PR was rolled into #28

riley-stride pushed a commit that referenced this pull request Sep 5, 2022
Update osmosis seeds to include whats in the binary
asalzmann pushed a commit that referenced this pull request Jan 25, 2024
nit cleanup changes after scaffolding
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.

2 participants