From acd3e582f8cbf1234d9dacf6d8f6e6290a517a52 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 23 Oct 2023 23:31:39 +0900 Subject: [PATCH 1/3] add unfinalized eki support Signed-off-by: Jun Kimura --- go.mod | 2 +- go.sum | 4 +- relay/cmd.go | 12 +-- relay/db.go | 104 +++++++++++++++++++++++ relay/lcp.go | 213 ++++++++++++++++++++++++++++-------------------- relay/prover.go | 12 ++- 6 files changed, 244 insertions(+), 103 deletions(-) create mode 100644 relay/db.go diff --git a/go.mod b/go.mod index d70339d..ef95327 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/ethereum/go-ethereum v1.12.0 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/hyperledger-labs/yui-relayer v0.4.15 + github.com/hyperledger-labs/yui-relayer v0.4.14 github.com/oasisprotocol/oasis-core/go v0.2201.11 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.16.0 diff --git a/go.sum b/go.sum index 2fe6ea5..f26f2f2 100644 --- a/go.sum +++ b/go.sum @@ -715,8 +715,8 @@ github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= -github.com/hyperledger-labs/yui-relayer v0.4.15 h1:kzZJFDvz6SexAfXFDbAo7CyidCN8lIh8KQSnPJQxNJc= -github.com/hyperledger-labs/yui-relayer v0.4.15/go.mod h1:Hdc/ERCPDhbipri45/U6+/3kDH7EttIWGdql+Rd3tZg= +github.com/hyperledger-labs/yui-relayer v0.4.14 h1:cuQwwhGjb52fT/qgKuYLW6FI/phnrUwFkEHoJWm+d/s= +github.com/hyperledger-labs/yui-relayer v0.4.14/go.mod h1:Hdc/ERCPDhbipri45/U6+/3kDH7EttIWGdql+Rd3tZg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= diff --git a/relay/cmd.go b/relay/cmd.go index 83f11c6..91d3a9d 100644 --- a/relay/cmd.go +++ b/relay/cmd.go @@ -2,7 +2,6 @@ package relay import ( "context" - "log" "github.com/hyperledger-labs/yui-relayer/config" "github.com/hyperledger-labs/yui-relayer/core" @@ -47,16 +46,7 @@ func updateEnclaveKeyCmd(ctx *config.Context) *cobra.Command { target = c[dst] } prover := target.Prover.(*Prover) - updated, err := prover.updateActiveEnclaveKeyIfNeeded(context.TODO()) - if err != nil { - return err - } - if updated { - log.Println("Active enclave key is updated") - } else { - log.Println("No need to update the active enclave key") - } - return nil + return prover.UpdateEKIfNeeded(context.TODO()) }, } return srcFlag(cmd) diff --git a/relay/db.go b/relay/db.go new file mode 100644 index 0000000..d3d5291 --- /dev/null +++ b/relay/db.go @@ -0,0 +1,104 @@ +package relay + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "log" + "os" + "path/filepath" + + "github.com/datachainlab/lcp-go/relay/enclave" + "github.com/hyperledger-labs/yui-relayer/core" +) + +const ( + lastFinalizedEnclaveKeyInfoFile = "last_finalized_eki" + lastUnfinalizedEnclaveKeyInfoFile = "last_unfinalized_eki" +) + +var ErrEnclaveKeyInfoNotFound = errors.New("enclave key info not found") + +type unfinalizedEKI struct { + Info *enclave.EnclaveKeyInfo `json:"info"` + MsgIDBytes []byte `json:"msg_id_bytes"` +} + +func (pr *Prover) dbPath() string { + return filepath.Join(pr.homePath, "lcp", pr.originChain.ChainID()) +} + +func (pr *Prover) lastEnclaveKeyInfoFilePath(finalized bool) string { + if finalized { + return filepath.Join(pr.dbPath(), lastFinalizedEnclaveKeyInfoFile) + } else { + return filepath.Join(pr.dbPath(), lastUnfinalizedEnclaveKeyInfoFile) + } +} + +func (pr *Prover) loadLastFinalizedEnclaveKey(ctx context.Context) (*enclave.EnclaveKeyInfo, error) { + path := pr.lastEnclaveKeyInfoFilePath(true) + bz, err := os.ReadFile(path) + if err != nil { + if os.IsNotExist(err) { + return nil, fmt.Errorf("%v not found: %w", path, ErrEnclaveKeyInfoNotFound) + } + return nil, err + } + var eki enclave.EnclaveKeyInfo + if err := json.Unmarshal(bz, &eki); err != nil { + return nil, err + } + return &eki, nil +} + +func (pr *Prover) loadLastUnfinalizedEnclaveKey(ctx context.Context) (*enclave.EnclaveKeyInfo, core.MsgID, error) { + path := pr.lastEnclaveKeyInfoFilePath(false) + bz, err := os.ReadFile(path) + if err != nil { + if os.IsNotExist(err) { + return nil, nil, fmt.Errorf("%v not found: %w", path, ErrEnclaveKeyInfoNotFound) + } + return nil, nil, err + } + var ueki unfinalizedEKI + if err := json.Unmarshal(bz, &ueki); err != nil { + return nil, nil, err + } + var unfinalizedMsgID core.MsgID + if err := pr.codec.UnmarshalInterface(ueki.MsgIDBytes, &unfinalizedMsgID); err != nil { + return nil, nil, err + } + return ueki.Info, unfinalizedMsgID, nil +} + +func (pr *Prover) saveFinalizedEnclaveKeyInfo(ctx context.Context, eki *enclave.EnclaveKeyInfo) error { + log.Println("save finalized enclave key info") + bz, err := json.Marshal(eki) + if err != nil { + return err + } + return os.WriteFile(pr.lastEnclaveKeyInfoFilePath(true), bz, 0600) +} + +func (pr *Prover) saveUnfinalizedEnclaveKeyInfo(ctx context.Context, eki *enclave.EnclaveKeyInfo, msgID core.MsgID) error { + log.Println("save unfinalized enclave key info") + msgIDBytes, err := pr.codec.MarshalInterface(msgID) + if err != nil { + return err + } + bz, err := json.Marshal(unfinalizedEKI{ + Info: eki, + MsgIDBytes: msgIDBytes, + }) + if err != nil { + return err + } + return os.WriteFile(pr.lastEnclaveKeyInfoFilePath(false), bz, 0600) +} + +func (pr *Prover) removeUnfinalizedEnclaveKeyInfo(ctx context.Context) error { + log.Println("remove unfinalized enclave key info") + return os.Remove(pr.lastEnclaveKeyInfoFilePath(false)) +} diff --git a/relay/lcp.go b/relay/lcp.go index dcbd9be..d9c318a 100644 --- a/relay/lcp.go +++ b/relay/lcp.go @@ -2,13 +2,9 @@ package relay import ( "context" - "encoding/json" "errors" "fmt" - "io" "log" - "os" - "path/filepath" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -24,149 +20,190 @@ import ( "github.com/datachainlab/lcp-go/sgx/ias" ) -const lastEnclaveKeyInfoFile = "last_eki" - -var ErrLastEnclaveKeyInfoNotFound = errors.New("last enclave key info not found") - -func (pr *Prover) loadLastEnclaveKey(ctx context.Context) (*enclave.EnclaveKeyInfo, error) { - path, err := pr.lastEnclaveKeyInfoFilePath() +// UpdateEKIIfNeeded checks if the enclave key needs to be updated +func (pr *Prover) UpdateEKIfNeeded(ctx context.Context) error { + updateNeeded, err := pr.loadEKIAndCheckUpdateNeeded(ctx) if err != nil { - return nil, err + return err } - bz, err := os.ReadFile(path) - if err != nil { - if os.IsNotExist(err) { - return nil, fmt.Errorf("%v not found: %w", path, ErrLastEnclaveKeyInfoNotFound) - } - return nil, err + log.Printf("loadEKIAndCheckUpdateNeeded: updateNeeded=%v", updateNeeded) + if !updateNeeded { + return nil } - var eki enclave.EnclaveKeyInfo - if err := json.Unmarshal(bz, &eki); err != nil { - return nil, err - } - return &eki, nil -} -func (pr *Prover) saveLastEnclaveKey(ctx context.Context, eki *enclave.EnclaveKeyInfo) error { - src, err := os.CreateTemp(os.TempDir(), lastEnclaveKeyInfoFile) - if err != nil { - return err - } - defer src.Close() + // if updateNeeded is true, + // query new key and register key and set it to memory and save it to file - bz, err := json.Marshal(eki) - if err != nil { - return err - } + pr.activeEnclaveKey, pr.unfinalizedMsgID = nil, nil + + log.Println("need to get a new enclave key") - if err = os.WriteFile(src.Name(), bz, 0600); err != nil { + eki, err := pr.selectNewEnclaveKey(ctx) + if err != nil { return err } + log.Printf("selected available enclave key: %#v", eki) - path, err := pr.lastEnclaveKeyInfoFilePath() + msgID, err := pr.registerEnclaveKey(eki) if err != nil { return err } - dst, err := os.Create(path) + finalized, success, err := pr.checkMsgStatus(msgID) if err != nil { return err + } else if !success { + return fmt.Errorf("msg(id=%v) execution failed", msgID) } - defer dst.Close() - if _, err = io.Copy(dst, src); err != nil { - return err + if finalized { + // this path is for chans have instant finality + // if the msg is finalized, save the enclave key info as finalized + if err := pr.saveFinalizedEnclaveKeyInfo(ctx, eki); err != nil { + return err + } + pr.activeEnclaveKey = eki + } else { + // if the msg is not finalized, save the enclave key info as unfinalized + if err := pr.saveUnfinalizedEnclaveKeyInfo(ctx, eki, msgID); err != nil { + return err + } + pr.activeEnclaveKey = eki + pr.unfinalizedMsgID = msgID } return nil } -func (pr *Prover) lastEnclaveKeyInfoFilePath() (string, error) { - path := filepath.Join(pr.homePath, "lcp", pr.originChain.ChainID()) - if err := os.MkdirAll(path, os.ModePerm); err != nil { - return "", err - } - return filepath.Join(path, lastEnclaveKeyInfoFile), nil -} - -// checkUpdateNeeded checks if the enclave key needs to be updated +// checkEKIUpdateNeeded checks if the enclave key needs to be updated // if the enclave key is missing or expired, it returns true -func (pr *Prover) checkUpdateNeeded(ctx context.Context, timestamp time.Time, eki *enclave.EnclaveKeyInfo) bool { +func (pr *Prover) checkEKIUpdateNeeded(ctx context.Context, timestamp time.Time, eki *enclave.EnclaveKeyInfo) bool { attestationTime := time.Unix(int64(eki.AttestationTime), 0) // TODO consider appropriate buffer time // For now, a half of expiration is used as a buffer time if timestamp.After(attestationTime.Add(time.Duration(pr.config.KeyExpiration) * time.Second / 2)) { + log.Printf("checkEKIUpdateNeeded: enclave key '%x' is expired", eki.EnclaveKeyAddress) return true } // check if the enclave key is still available in the LCP service _, err := pr.lcpServiceClient.EnclaveKey(ctx, &enclave.QueryEnclaveKeyRequest{EnclaveKeyAddress: eki.EnclaveKeyAddress}) if err != nil { - log.Printf("checkUpdateNeeded: enclave key '%x' not found: error=%v", eki.EnclaveKeyAddress, err) + log.Printf("checkEKIUpdateNeeded: enclave key '%x' not found: error=%v", eki.EnclaveKeyAddress, err) return true } return false } -// ensureAvailableEnclaveKeyExists ensures that the active enclave key exists -// otherwise it tries to get a new enclave key -func (pr *Prover) ensureAvailableEnclaveKeyExists(ctx context.Context) error { - updated, err := pr.updateActiveEnclaveKeyIfNeeded(ctx) +// isFinalizedMsg checks if the given msg is finalized in the origin chain +// and returns (finalized, success, error) +// finalized: true if the msg is finalized +// success: true if the msg is successfully executed in the origin chain +// error: non-nil if the msg may not exist in the origin chain +func (pr *Prover) checkMsgStatus(msgID core.MsgID) (bool, bool, error) { + lfHeader, err := pr.originProver.GetLatestFinalizedHeader() if err != nil { - return err + return false, false, err } - log.Printf("updateActiveEnclaveKeyIfNeeded: updated=%v", updated) - return nil + msgRes, err := pr.originChain.GetMsgResult(msgID) + if err != nil { + return false, false, err + } else if ok, failureReason := msgRes.Status(); !ok { + log.Printf("msg(%s) execution failed: %v", msgID.String(), failureReason) + return false, false, nil + } + return msgRes.BlockHeight().LTE(lfHeader.GetHeight()), true, nil } -// updateActiveEnclaveKeyIfNeeded updates a key if key is missing or expired -func (pr *Prover) updateActiveEnclaveKeyIfNeeded(ctx context.Context) (bool, error) { +// if returns true, query new key and register key and set it to memory +func (pr *Prover) loadEKIAndCheckUpdateNeeded(ctx context.Context) (bool, error) { if err := pr.initServiceClient(); err != nil { return false, err } now := time.Now() - // 1. check if the active enclave key is missing or expired - + // no active enclave key in memory if pr.activeEnclaveKey == nil { - // load last key if exists - lastEnclaveKey, err := pr.loadLastEnclaveKey(ctx) - if err == nil { - if !pr.checkUpdateNeeded(ctx, now, lastEnclaveKey) { - pr.activeEnclaveKey = lastEnclaveKey - return false, nil - } else { - log.Printf("last enclave key '0x%x' is found, but needs to be updated", lastEnclaveKey.EnclaveKeyAddress) + // 1: load the last unfinalized enclave key if exists + // 2: load the last finalized enclave key if exists + // 3: select a new enclave key from the LCP service (i.e. return true) + + log.Println("no active enclave key in memory") + + if eki, msgID, err := pr.loadLastUnfinalizedEnclaveKey(ctx); err == nil { + log.Println("load last unfinalized enclave key into memory") + pr.activeEnclaveKey = eki + pr.unfinalizedMsgID = msgID + } else if errors.Is(err, ErrEnclaveKeyInfoNotFound) { + log.Println("no unfinalized enclave key info found") + eki, err := pr.loadLastFinalizedEnclaveKey(ctx) + if err != nil { + if errors.Is(err, ErrEnclaveKeyInfoNotFound) { + log.Println("no enclave key info found") + return true, nil + } + return false, err } - } else if errors.Is(err, ErrLastEnclaveKeyInfoNotFound) { - log.Printf("last enclave key not found: error=%v", err) + log.Println("load last finalized enclave key into memory") + pr.activeEnclaveKey = eki + pr.unfinalizedMsgID = nil } else { return false, err } - } else if !pr.checkUpdateNeeded(ctx, now, pr.activeEnclaveKey) { - return false, nil } - // 2. query the active enclave key from the LCP service + // finalized enclave key + if pr.unfinalizedMsgID == nil { + log.Println("active enclave key is finalized") + // check if the enclave key is still available in the LCP service and not expired + return pr.checkEKIUpdateNeeded(ctx, now, pr.activeEnclaveKey), nil + } - log.Println("need to get a new enclave key") + // unfinalized enclave key - eki, err := pr.selectNewEnclaveKey(ctx) - if err != nil { - return false, err + log.Println("active enclave key is unfinalized") + + if _, err := pr.originChain.GetMsgResult(pr.unfinalizedMsgID); err != nil { + // err means that the msg is not included in the latest block + log.Printf("msg(%s) is not included in the latest block: error=%v", pr.unfinalizedMsgID.String(), err) + if err := pr.removeUnfinalizedEnclaveKeyInfo(ctx); err != nil { + return false, err + } + return true, nil } - log.Printf("selected available enclave key: %#v", eki) - msgID, err := pr.registerEnclaveKey(eki) + + finalized, success, err := pr.checkMsgStatus(pr.unfinalizedMsgID) + log.Printf("check unfinalized msg(%s) status: finalized=%v success=%v error=%v", pr.unfinalizedMsgID.String(), finalized, success, err) if err != nil { return false, err + } else if !success { + // tx is failed, so remove the unfinalized enclave key info + log.Printf("msg(%s) execution failed", pr.unfinalizedMsgID.String()) + if err := pr.removeUnfinalizedEnclaveKeyInfo(ctx); err != nil { + return false, err + } + return true, nil + } else if finalized { + // tx is successfully executed and finalized + log.Printf("msg(%s) is finalized", pr.unfinalizedMsgID.String()) + if pr.checkEKIUpdateNeeded(ctx, now, pr.activeEnclaveKey) { + return true, nil + } + log.Printf("save enclave key info as finalized: enclave key address=%x", pr.activeEnclaveKey.EnclaveKeyAddress) + if err := pr.saveFinalizedEnclaveKeyInfo(ctx, pr.activeEnclaveKey); err != nil { + return false, err + } + log.Printf("remove old unfinalized enclave key info: enclave key address=%x", pr.activeEnclaveKey.EnclaveKeyAddress) + if err := pr.removeUnfinalizedEnclaveKeyInfo(ctx); err != nil { + return false, err + } + pr.unfinalizedMsgID = nil + return false, nil + } else { + // tx is successfully executed but not finalized yet + log.Printf("msg(%s) is not finalized yet", pr.unfinalizedMsgID.String()) + return pr.checkEKIUpdateNeeded(ctx, now, pr.activeEnclaveKey), nil } - // TODO should we wait for the block that contains a tx to be finalized? - log.Printf("enclave key successfully registered: msgID=%v eki=%#v", msgID.String(), eki) - if err := pr.saveLastEnclaveKey(ctx, eki); err != nil { - return false, err - } - pr.activeEnclaveKey = eki - return true, nil } // selectNewEnclaveKey selects a new enclave key from the LCP service @@ -307,7 +344,7 @@ func (pr *Prover) registerEnclaveKey(eki *enclave.EnclaveKeyInfo) (core.MsgID, e func activateClient(pathEnd *core.PathEnd, src, dst *core.ProvableChain) error { srcProver := src.Prover.(*Prover) - if err := srcProver.ensureAvailableEnclaveKeyExists(context.TODO()); err != nil { + if err := srcProver.UpdateEKIfNeeded(context.TODO()); err != nil { return err } diff --git a/relay/prover.go b/relay/prover.go index af779fe..cdc5c32 100644 --- a/relay/prover.go +++ b/relay/prover.go @@ -3,6 +3,7 @@ package relay import ( "context" "fmt" + "os" "time" "github.com/cosmos/cosmos-sdk/codec" @@ -29,7 +30,13 @@ type Prover struct { path *core.PathEnd lcpServiceClient LCPServiceClient + + // state + // registered key info for requesting lcp to generate proof. activeEnclaveKey *enclave.EnclaveKeyInfo + // if not nil, the key is finalized. + // if nil, the key is not finalized yet. + unfinalizedMsgID core.MsgID } var ( @@ -68,6 +75,9 @@ func (pr *Prover) Init(homePath string, timeout time.Duration, codec codec.Proto if err := pr.originProver.Init(homePath, timeout, codec, debug); err != nil { return err } + if err := os.MkdirAll(pr.dbPath(), os.ModePerm); err != nil { + return err + } pr.homePath = homePath pr.codec = codec return nil @@ -153,7 +163,7 @@ func (pr *Prover) GetLatestFinalizedHeader() (latestFinalizedHeader core.Header, // The order of the returned header slice should be as: [..., ] // if the header slice's length == nil and err == nil, the relayer should skips the update-client func (pr *Prover) SetupHeadersForUpdate(dstChain core.ChainInfoICS02Querier, latestFinalizedHeader core.Header) ([]core.Header, error) { - if err := pr.ensureAvailableEnclaveKeyExists(context.TODO()); err != nil { + if err := pr.UpdateEKIfNeeded(context.TODO()); err != nil { return nil, err } From 64756338019196780a9e43cd28cfbe3257edc17c Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Wed, 25 Oct 2023 09:46:44 +0900 Subject: [PATCH 2/3] check if ek is not expired in `selectNewEnclaveKey` Signed-off-by: Jun Kimura --- relay/lcp.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/relay/lcp.go b/relay/lcp.go index d9c318a..2097a48 100644 --- a/relay/lcp.go +++ b/relay/lcp.go @@ -80,8 +80,11 @@ func (pr *Prover) checkEKIUpdateNeeded(ctx context.Context, timestamp time.Time, attestationTime := time.Unix(int64(eki.AttestationTime), 0) // TODO consider appropriate buffer time + updateTime := attestationTime.Add(time.Duration(pr.config.KeyExpiration) * time.Second / 2) + log.Printf("checkEKIUpdateNeeded: enclave_key=%x now=%v attestation_time=%v expiration=%v update_time=%v", eki.EnclaveKeyAddress, timestamp.Unix(), attestationTime.Unix(), pr.config.KeyExpiration, updateTime.Unix()) + // For now, a half of expiration is used as a buffer time - if timestamp.After(attestationTime.Add(time.Duration(pr.config.KeyExpiration) * time.Second / 2)) { + if timestamp.After(updateTime) { log.Printf("checkEKIUpdateNeeded: enclave key '%x' is expired", eki.EnclaveKeyAddress) return true } @@ -223,6 +226,10 @@ func (pr *Prover) selectNewEnclaveKey(ctx context.Context) (*enclave.EnclaveKeyI if err != nil { return nil, err } + if pr.checkEKIUpdateNeeded(ctx, time.Now(), eki) { + log.Printf("key '%x' is not allowed to use because of expiration", eki.EnclaveKeyAddress) + continue + } if !pr.validateISVEnclaveQuoteStatus(avr.ISVEnclaveQuoteStatus) { log.Printf("key '%x' is not allowed to use because of ISVEnclaveQuoteStatus: %v", eki.EnclaveKeyAddress, avr.ISVEnclaveQuoteStatus) continue From 38f13461666c52c0ca8de6c503a8e702d5cebb6b Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Wed, 25 Oct 2023 14:12:35 +0900 Subject: [PATCH 3/3] update to relayer v0.4.17 and send `registerEnclaveKey` msg to verifier chain instead of origin chain Signed-off-by: Jun Kimura --- go.mod | 2 +- go.sum | 4 +-- relay/cmd.go | 7 +++-- relay/lcp.go | 31 ++++++++++--------- relay/prover.go | 4 +-- .../tm2tm/configs/templates/ibc-0.json.tpl | 6 +++- .../tm2tm/configs/templates/ibc-1.json.tpl | 6 +++- tests/e2e/cases/tm2tm/scripts/handshake | 3 -- 8 files changed, 36 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index ef95327..0380dd8 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/ethereum/go-ethereum v1.12.0 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/hyperledger-labs/yui-relayer v0.4.14 + github.com/hyperledger-labs/yui-relayer v0.4.17 github.com/oasisprotocol/oasis-core/go v0.2201.11 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.16.0 diff --git a/go.sum b/go.sum index f26f2f2..3dde9f6 100644 --- a/go.sum +++ b/go.sum @@ -715,8 +715,8 @@ github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= -github.com/hyperledger-labs/yui-relayer v0.4.14 h1:cuQwwhGjb52fT/qgKuYLW6FI/phnrUwFkEHoJWm+d/s= -github.com/hyperledger-labs/yui-relayer v0.4.14/go.mod h1:Hdc/ERCPDhbipri45/U6+/3kDH7EttIWGdql+Rd3tZg= +github.com/hyperledger-labs/yui-relayer v0.4.17 h1:cjXYvfkTFiJEpXLtaMPQ7Q6Kd3vFvwQ0FAZ3JncoEz0= +github.com/hyperledger-labs/yui-relayer v0.4.17/go.mod h1:Hdc/ERCPDhbipri45/U6+/3kDH7EttIWGdql+Rd3tZg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= diff --git a/relay/cmd.go b/relay/cmd.go index 91d3a9d..2abdc50 100644 --- a/relay/cmd.go +++ b/relay/cmd.go @@ -38,15 +38,18 @@ func updateEnclaveKeyCmd(ctx *config.Context) *cobra.Command { return err } var ( - target *core.ProvableChain + target *core.ProvableChain + verifier *core.ProvableChain ) if viper.GetBool(flagSrc) { target = c[src] + verifier = c[dst] } else { target = c[dst] + verifier = c[src] } prover := target.Prover.(*Prover) - return prover.UpdateEKIfNeeded(context.TODO()) + return prover.UpdateEKIfNeeded(context.TODO(), verifier) }, } return srcFlag(cmd) diff --git a/relay/lcp.go b/relay/lcp.go index 2097a48..63d35f4 100644 --- a/relay/lcp.go +++ b/relay/lcp.go @@ -21,8 +21,8 @@ import ( ) // UpdateEKIIfNeeded checks if the enclave key needs to be updated -func (pr *Prover) UpdateEKIfNeeded(ctx context.Context) error { - updateNeeded, err := pr.loadEKIAndCheckUpdateNeeded(ctx) +func (pr *Prover) UpdateEKIfNeeded(ctx context.Context, verifier core.FinalityAwareChain) error { + updateNeeded, err := pr.loadEKIAndCheckUpdateNeeded(ctx, verifier) if err != nil { return err } @@ -44,11 +44,11 @@ func (pr *Prover) UpdateEKIfNeeded(ctx context.Context) error { } log.Printf("selected available enclave key: %#v", eki) - msgID, err := pr.registerEnclaveKey(eki) + msgID, err := pr.registerEnclaveKey(verifier, eki) if err != nil { return err } - finalized, success, err := pr.checkMsgStatus(msgID) + finalized, success, err := checkMsgStatus(verifier, msgID) if err != nil { return err } else if !success { @@ -102,12 +102,12 @@ func (pr *Prover) checkEKIUpdateNeeded(ctx context.Context, timestamp time.Time, // finalized: true if the msg is finalized // success: true if the msg is successfully executed in the origin chain // error: non-nil if the msg may not exist in the origin chain -func (pr *Prover) checkMsgStatus(msgID core.MsgID) (bool, bool, error) { - lfHeader, err := pr.originProver.GetLatestFinalizedHeader() +func checkMsgStatus(verifier core.FinalityAwareChain, msgID core.MsgID) (bool, bool, error) { + lfHeader, err := verifier.GetLatestFinalizedHeader() if err != nil { return false, false, err } - msgRes, err := pr.originChain.GetMsgResult(msgID) + msgRes, err := verifier.GetMsgResult(msgID) if err != nil { return false, false, err } else if ok, failureReason := msgRes.Status(); !ok { @@ -118,7 +118,7 @@ func (pr *Prover) checkMsgStatus(msgID core.MsgID) (bool, bool, error) { } // if returns true, query new key and register key and set it to memory -func (pr *Prover) loadEKIAndCheckUpdateNeeded(ctx context.Context) (bool, error) { +func (pr *Prover) loadEKIAndCheckUpdateNeeded(ctx context.Context, verifier core.FinalityAwareChain) (bool, error) { if err := pr.initServiceClient(); err != nil { return false, err } @@ -166,7 +166,7 @@ func (pr *Prover) loadEKIAndCheckUpdateNeeded(ctx context.Context) (bool, error) log.Println("active enclave key is unfinalized") - if _, err := pr.originChain.GetMsgResult(pr.unfinalizedMsgID); err != nil { + if _, err := verifier.GetMsgResult(pr.unfinalizedMsgID); err != nil { // err means that the msg is not included in the latest block log.Printf("msg(%s) is not included in the latest block: error=%v", pr.unfinalizedMsgID.String(), err) if err := pr.removeUnfinalizedEnclaveKeyInfo(ctx); err != nil { @@ -175,7 +175,7 @@ func (pr *Prover) loadEKIAndCheckUpdateNeeded(ctx context.Context) (bool, error) return true, nil } - finalized, success, err := pr.checkMsgStatus(pr.unfinalizedMsgID) + finalized, success, err := checkMsgStatus(verifier, pr.unfinalizedMsgID) log.Printf("check unfinalized msg(%s) status: finalized=%v success=%v error=%v", pr.unfinalizedMsgID.String(), finalized, success, err) if err != nil { return false, err @@ -319,7 +319,7 @@ func (pr *Prover) syncUpstreamHeader(includeState bool) ([]*elc.MsgUpdateClientR return responses, nil } -func (pr *Prover) registerEnclaveKey(eki *enclave.EnclaveKeyInfo) (core.MsgID, error) { +func (pr *Prover) registerEnclaveKey(verifier core.Chain, eki *enclave.EnclaveKeyInfo) (core.MsgID, error) { if err := ias.VerifyReport(eki.Report, eki.Signature, eki.SigningCert, time.Now()); err != nil { return nil, err } @@ -331,7 +331,7 @@ func (pr *Prover) registerEnclaveKey(eki *enclave.EnclaveKeyInfo) (core.MsgID, e Signature: eki.Signature, SigningCert: eki.SigningCert, } - signer, err := pr.originChain.GetAddress() + signer, err := verifier.GetAddress() if err != nil { return nil, err } @@ -339,7 +339,7 @@ func (pr *Prover) registerEnclaveKey(eki *enclave.EnclaveKeyInfo) (core.MsgID, e if err != nil { return nil, err } - ids, err := pr.originChain.SendMsgs([]sdk.Msg{msg}) + ids, err := verifier.SendMsgs([]sdk.Msg{msg}) if err != nil { return nil, err } @@ -351,7 +351,7 @@ func (pr *Prover) registerEnclaveKey(eki *enclave.EnclaveKeyInfo) (core.MsgID, e func activateClient(pathEnd *core.PathEnd, src, dst *core.ProvableChain) error { srcProver := src.Prover.(*Prover) - if err := srcProver.UpdateEKIfNeeded(context.TODO()); err != nil { + if err := srcProver.UpdateEKIfNeeded(context.TODO(), dst); err != nil { return err } @@ -394,9 +394,10 @@ func activateClient(pathEnd *core.PathEnd, src, dst *core.ProvableChain) error { type LCPQuerier struct { serviceClient LCPServiceClient clientID string + core.FinalityAwareChain } -var _ core.ChainInfoICS02Querier = (*LCPQuerier)(nil) +var _ core.FinalityAwareChain = (*LCPQuerier)(nil) func NewLCPQuerier(serviceClient LCPServiceClient, clientID string) LCPQuerier { return LCPQuerier{ diff --git a/relay/prover.go b/relay/prover.go index cdc5c32..955c40e 100644 --- a/relay/prover.go +++ b/relay/prover.go @@ -162,8 +162,8 @@ func (pr *Prover) GetLatestFinalizedHeader() (latestFinalizedHeader core.Header, // SetupHeadersForUpdate returns the finalized header and any intermediate headers needed to apply it to the client on the counterpaty chain // The order of the returned header slice should be as: [..., ] // if the header slice's length == nil and err == nil, the relayer should skips the update-client -func (pr *Prover) SetupHeadersForUpdate(dstChain core.ChainInfoICS02Querier, latestFinalizedHeader core.Header) ([]core.Header, error) { - if err := pr.UpdateEKIfNeeded(context.TODO()); err != nil { +func (pr *Prover) SetupHeadersForUpdate(dstChain core.FinalityAwareChain, latestFinalizedHeader core.Header) ([]core.Header, error) { + if err := pr.UpdateEKIfNeeded(context.TODO(), dstChain); err != nil { return nil, err } diff --git a/tests/e2e/cases/tm2tm/configs/templates/ibc-0.json.tpl b/tests/e2e/cases/tm2tm/configs/templates/ibc-0.json.tpl index 5afa818..a6db803 100644 --- a/tests/e2e/cases/tm2tm/configs/templates/ibc-0.json.tpl +++ b/tests/e2e/cases/tm2tm/configs/templates/ibc-0.json.tpl @@ -14,7 +14,11 @@ "@type": "/relayer.provers.lcp.config.ProverConfig", "origin_prover": { "@type": "/relayer.chains.tendermint.config.ProverConfig", - "trusting_period": "336h" + "trusting_period": "336h", + "refresh_threshold_rate": { + "numerator": 1, + "denominator": 2 + } }, "lcp_service_address": "localhost:50051", "mrenclave": "$MRENCLAVE", diff --git a/tests/e2e/cases/tm2tm/configs/templates/ibc-1.json.tpl b/tests/e2e/cases/tm2tm/configs/templates/ibc-1.json.tpl index 1789816..6335118 100644 --- a/tests/e2e/cases/tm2tm/configs/templates/ibc-1.json.tpl +++ b/tests/e2e/cases/tm2tm/configs/templates/ibc-1.json.tpl @@ -14,7 +14,11 @@ "@type": "/relayer.provers.lcp.config.ProverConfig", "origin_prover": { "@type": "/relayer.chains.tendermint.config.ProverConfig", - "trusting_period": "336h" + "trusting_period": "336h", + "refresh_threshold_rate": { + "numerator": 1, + "denominator": 2 + } }, "lcp_service_address": "localhost:50051", "mrenclave": "$MRENCLAVE", diff --git a/tests/e2e/cases/tm2tm/scripts/handshake b/tests/e2e/cases/tm2tm/scripts/handshake index 3e5545a..d6d261a 100755 --- a/tests/e2e/cases/tm2tm/scripts/handshake +++ b/tests/e2e/cases/tm2tm/scripts/handshake @@ -39,9 +39,6 @@ $RLY paths add $CHAINID_ONE $CHAINID_TWO $PATH_NAME --file=./configs/path.json retry 5 $RLY tx clients $PATH_NAME sleep 3 -retry 5 $RLY lcp update-enclave-key $PATH_NAME --src=true -retry 5 $RLY lcp update-enclave-key $PATH_NAME --src=false -sleep 3 retry 5 $RLY lcp activate-client $PATH_NAME --src=true retry 5 $RLY lcp activate-client $PATH_NAME --src=false sleep 3