diff --git a/light-clients/lcp/types/message.go b/light-clients/lcp/types/message.go index 9b20ce8..1c05948 100644 --- a/light-clients/lcp/types/message.go +++ b/light-clients/lcp/types/message.go @@ -3,6 +3,7 @@ package types import ( "bytes" "encoding/binary" + "encoding/json" "fmt" "math/big" "time" @@ -103,14 +104,18 @@ func (id StateID) EqualBytes(bz []byte) bool { return bytes.Equal(id[:], bz) } +func (id StateID) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf("\"%s\"", id.String())), nil +} + type UpdateStateProxyMessage struct { - PrevHeight *clienttypes.Height - PrevStateID *StateID - PostHeight clienttypes.Height - PostStateID StateID - Timestamp *big.Int - Context ValidationContext - EmittedStates []EmittedState + PrevHeight *clienttypes.Height `json:"prev_height"` + PrevStateID *StateID `json:"prev_state_id"` + PostHeight clienttypes.Height `json:"post_height"` + PostStateID StateID `json:"post_state_id"` + Timestamp *big.Int `json:"timestamp"` + Context ValidationContext `json:"context"` + EmittedStates []EmittedState `json:"emitted_states"` } type EmittedState struct { @@ -118,6 +123,20 @@ type EmittedState struct { State codectypes.Any } +func (es EmittedState) MarshalJSON() ([]byte, error) { + var es2 struct { + Height clienttypes.Height `json:"height"` + State struct { + TypeUrl string `json:"type_url"` + Value []byte `json:"value"` + } `json:"state"` + } + es2.Height = es.Height + es2.State.TypeUrl = es.State.TypeUrl + es2.State.Value = es.State.Value + return json.Marshal(es2) +} + type MisbehaviourProxyMessage struct { PrevStates []struct { Height clienttypes.Height @@ -143,10 +162,24 @@ func (EmptyValidationContext) Validate(time.Time) error { // TrustingPeriodValidationContext is the commitment context for a commitment that requires the current time to be within the trusting period. type TrustingPeriodValidationContext struct { - UntrustedHeaderTimestamp time.Time - TrustedStateTimestamp time.Time - TrustingPeriod big.Int - ClockDrift big.Int + UntrustedHeaderTimestamp time.Time `json:"untrusted_header_timestamp"` + TrustedStateTimestamp time.Time `json:"trusted_state_timestamp"` + TrustingPeriod big.Int `json:"trusting_period"` + ClockDrift big.Int `json:"clock_drift"` +} + +func (c TrustingPeriodValidationContext) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + UntrustedHeaderTimestamp *big.Int `json:"untrusted_header_timestamp"` + TrustedStateTimestamp *big.Int `json:"trusted_state_timestamp"` + TrustingPeriod *big.Int `json:"trusting_period"` + ClockDrift *big.Int `json:"clock_drift"` + }{ + UntrustedHeaderTimestamp: big.NewInt(c.UntrustedHeaderTimestamp.UnixNano()), + TrustedStateTimestamp: big.NewInt(c.TrustedStateTimestamp.UnixNano()), + TrustingPeriod: &c.TrustingPeriod, + ClockDrift: &c.ClockDrift, + }) } func DecodeTrustingPeriodValidationContext(timestamps, params [32]byte) *TrustingPeriodValidationContext { diff --git a/relay/cmd.go b/relay/cmd.go index 0e68083..a82949e 100644 --- a/relay/cmd.go +++ b/relay/cmd.go @@ -2,6 +2,8 @@ package relay import ( "context" + "encoding/json" + "fmt" "github.com/hyperledger-labs/yui-relayer/config" "github.com/hyperledger-labs/yui-relayer/core" @@ -110,7 +112,16 @@ func createELCCmd(ctx *config.Context) *cobra.Command { target = c[dst] } prover := target.Prover.(*Prover) - return prover.doCreateELC(viper.GetUint64(flagHeight)) + out, err := prover.doCreateELC(viper.GetUint64(flagHeight)) + if err != nil { + return err + } + bz, err := json.Marshal(out) + if err != nil { + return err + } + fmt.Println(string(bz)) + return nil }, } return heightFlag(srcFlag(cmd)) @@ -138,7 +149,16 @@ func updateELCCmd(ctx *config.Context) *cobra.Command { counterparty = c[src] } prover := target.Prover.(*Prover) - return prover.doUpdateELC(viper.GetString(flagELCClientID), counterparty) + out, err := prover.doUpdateELC(viper.GetString(flagELCClientID), counterparty) + if err != nil { + return err + } + bz, err := json.Marshal(out) + if err != nil { + return err + } + fmt.Println(string(bz)) + return nil }, } return elcClientIDFlag(srcFlag(cmd)) diff --git a/relay/lcp.go b/relay/lcp.go index 4f56a29..4754217 100644 --- a/relay/lcp.go +++ b/relay/lcp.go @@ -347,41 +347,53 @@ func (pr *Prover) registerEnclaveKey(verifier core.Chain, eki *enclave.EnclaveKe return ids[0], nil } +type CreateELCResult struct { + ELCClientID string `json:"elc_client_id"` + Message *lcptypes.UpdateStateProxyMessage `json:"message"` +} + // height: 0 means the latest height -func (pr *Prover) doCreateELC(height uint64) error { +func (pr *Prover) doCreateELC(height uint64) (*CreateELCResult, error) { header, err := pr.originProver.GetLatestFinalizedHeader() if err != nil { - return err + return nil, err } latestHeight := header.GetHeight() if height == 0 { height = latestHeight.GetRevisionHeight() } else if height >= latestHeight.GetRevisionHeight() { - return fmt.Errorf("height %v is greater than the latest height %v", height, latestHeight.GetRevisionHeight()) + return nil, fmt.Errorf("height %v is greater than the latest height %v", height, latestHeight.GetRevisionHeight()) } h := clienttypes.NewHeight(latestHeight.GetRevisionNumber(), height) log.GetLogger().Info("try to create ELC client", "height", h) res, err := pr.createELC(h) if err != nil { - return err + return nil, err } log.GetLogger().Info("created ELC client", "client_id", res.ClientId) // ensure the message is valid msg, err := lcptypes.EthABIDecodeHeaderedProxyMessage(res.Message) if err != nil { - return err + return nil, err } m, err := msg.GetUpdateStateProxyMessage() if err != nil { - return err + return nil, err } log.GetLogger().Info("created state", "post_height", m.PostHeight, "post_state_id", m.PostStateID.String(), "timestamp", m.Timestamp.String()) - return err + return &CreateELCResult{ + ELCClientID: res.ClientId, + Message: m, + }, nil +} + +type UpdateELCResult struct { + Messages []*lcptypes.UpdateStateProxyMessage `json:"messages"` } -func (pr *Prover) doUpdateELC(elcClientID string, counterparty core.FinalityAwareChain) error { +func (pr *Prover) doUpdateELC(elcClientID string, counterparty core.FinalityAwareChain) (*UpdateELCResult, error) { if err := pr.UpdateEKIfNeeded(context.TODO(), counterparty); err != nil { - return err + return nil, err } if elcClientID == "" { elcClientID = pr.config.ElcClientId @@ -389,24 +401,30 @@ func (pr *Prover) doUpdateELC(elcClientID string, counterparty core.FinalityAwar log.GetLogger().Info("try to update the ELC client", "elc_client_id", elcClientID) updates, err := pr.updateELC(elcClientID, false) if err != nil { - return err + return nil, err } if len(updates) == 0 { log.GetLogger().Info("no update is needed") - return nil + return &UpdateELCResult{ + Messages: []*lcptypes.UpdateStateProxyMessage{}, + }, nil } + var msgs []*lcptypes.UpdateStateProxyMessage for _, update := range updates { commitment, err := lcptypes.EthABIDecodeHeaderedProxyMessage(update.Message) if err != nil { - return err + return nil, err } - usm, err := commitment.GetUpdateStateProxyMessage() + msg, err := commitment.GetUpdateStateProxyMessage() if err != nil { - return err + return nil, err } - log.GetLogger().Info("updated state", "prev_height", usm.PrevHeight, "prev_state_id", usm.PrevStateID.String(), "post_height", usm.PostHeight, "post_state_id", usm.PostStateID.String(), "timestamp", usm.Timestamp.String()) + log.GetLogger().Info("updated state", "prev_height", msg.PrevHeight, "prev_state_id", msg.PrevStateID.String(), "post_height", msg.PostHeight, "post_state_id", msg.PostStateID.String(), "timestamp", msg.Timestamp.String()) + msgs = append(msgs, msg) } - return nil + return &UpdateELCResult{ + Messages: msgs, + }, nil } func (pr *Prover) createELC(height exported.Height) (*elc.MsgCreateClientResponse, error) { diff --git a/tests/e2e/cases/tm2tm/scripts/test-elc-update b/tests/e2e/cases/tm2tm/scripts/test-elc-update index d69dd13..8af8cf9 100755 --- a/tests/e2e/cases/tm2tm/scripts/test-elc-update +++ b/tests/e2e/cases/tm2tm/scripts/test-elc-update @@ -4,19 +4,14 @@ set -eu RLY="${RLY_BIN} --debug" -output=$(${RLY} lcp create-elc ibc01 --src 2>&1) -if [[ ! $output =~ "created ELC client: 07-tendermint-2" ]]; then - echo "unexpected output: $output" - exit 1 -fi -output=$(${RLY} lcp create-elc ibc01 --src=false 2>&1) -if [[ ! $output =~ "created ELC client: 07-tendermint-3" ]]; then - echo "unexpected output: $output" - exit 1 -fi +src_elc_client_id=$(${RLY} lcp create-elc ibc01 --src | jq -r '.elc_client_id') +dst_elc_client_id=$(${RLY} lcp create-elc ibc01 --src=false | jq -r '.elc_client_id') + +echo "src: ELC client id: ${src_elc_client_id}" +echo "dst: ELC client id: ${dst_elc_client_id}" echo "sleeping for 5 seconds" sleep 5 -${RLY} lcp update-elc ibc01 --src --elc_client_id=07-tendermint-2 -${RLY} lcp update-elc ibc01 --src=false --elc_client_id=07-tendermint-3 +${RLY} lcp update-elc ibc01 --src --elc_client_id=${src_elc_client_id} +${RLY} lcp update-elc ibc01 --src=false --elc_client_id=${dst_elc_client_id}