Skip to content

feat: add verifier for icon. #105

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

Merged
merged 9 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ func createClientsCmd(a *appState) *cobra.Command {
return fmt.Errorf("key %s not found on dst chain %s", c[dst].ChainProvider.Key(), c[dst].ChainID())
}

// TODO: make iconStartHeight compulsory
// if iconStartHeight is not given it can create confusion as starting relay at any time could miss number of btp block update_client
clientSrc, clientDst, err := c[src].CreateClients(cmd.Context(), c[dst], allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, override, customClientTrustingPeriod, a.config.memo(cmd), iconStartHeight)
if err != nil {
return err
Expand Down Expand Up @@ -335,6 +337,7 @@ func upgradeClientsCmd(a *appState) *cobra.Command {
return cmd
}

// TODO: method has side_effect
func createConnectionCmd(a *appState) *cobra.Command {
cmd := &cobra.Command{
Use: "connection path_name",
Expand Down
6 changes: 6 additions & 0 deletions relayer/chains/archway/archway_chain_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ const (
latestHeightQueryRetryDelay = 1 * time.Second
latestHeightQueryRetries = 5

// TODO: review transfer to providerConfig
defaultMinQueryLoopDuration = 1 * time.Second
defaultBalanceUpdateWaitDuration = 60 * time.Second
inSyncNumBlocksThreshold = 2
Expand Down Expand Up @@ -305,6 +306,7 @@ func (ccp *ArchwayChainProcessor) initializeChannelState(ctx context.Context) er
}

func (ccp *ArchwayChainProcessor) queryCycle(ctx context.Context, persistence *queryCyclePersistence) error {
// TODO : review if redundent remove
status, err := ccp.nodeStatusWithRetry(ctx)
if err != nil {
// don't want to cause ArchwayChainProcessor to quit here, can retry again next cycle.
Expand Down Expand Up @@ -355,6 +357,8 @@ func (ccp *ArchwayChainProcessor) queryCycle(ctx context.Context, persistence *q

chainID := ccp.chainProvider.ChainId()

// TODO review: max block sync
//
for i := persistence.latestQueriedBlock + 1; i <= persistence.latestHeight; i++ {
var eg errgroup.Group
var blockRes *ctypes.ResultBlockResults
Expand Down Expand Up @@ -451,6 +455,8 @@ func (ccp *ArchwayChainProcessor) queryCycle(ctx context.Context, persistence *q
return nil
}

// TODO: review add verifier

func (ccp *ArchwayChainProcessor) CollectMetrics(ctx context.Context, persistence *queryCyclePersistence) {
ccp.CurrentBlockHeight(ctx, persistence)

Expand Down
1 change: 0 additions & 1 deletion relayer/chains/icon/cryptoutils/merkle_proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"math/bits"

"github.com/cosmos/relayer/v2/relayer/chains/icon/types"

"github.com/cosmos/relayer/v2/relayer/common"
"github.com/icon-project/IBC-Integration/libraries/go/common/icon"
)
Expand Down
2 changes: 2 additions & 0 deletions relayer/chains/icon/event_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ func (pi *packetInfo) parseAttrs(log *zap.Logger, event types.EventLog) {
packetData := event.Indexed[1]
var packet icon.Packet
if err := proto.Unmarshal(packetData, &packet); err != nil {

log.Error("failed to unmarshal packet")
// TODO: review return if parseAttrs add panic
}
pi.SourcePort = packet.SourcePort
pi.SourceChannel = packet.SourceChannel
Expand Down
104 changes: 91 additions & 13 deletions relayer/chains/icon/icon_chain_processor.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package icon

import (
"bytes"
"context"
"fmt"
"sort"
Expand Down Expand Up @@ -61,6 +62,14 @@ type IconChainProcessor struct {

// metrics to monitor lifetime of processor
metrics *processor.PrometheusMetrics

verifier *Verifier
}

type Verifier struct {
nextProofContext [][]byte
verifiedHeight int64
prevNetworkSectionHash []byte
}

func NewIconChainProcessor(log *zap.Logger, provider *IconProvider, metrics *processor.PrometheusMetrics) *IconChainProcessor {
Expand Down Expand Up @@ -144,7 +153,7 @@ func (icp *IconChainProcessor) Run(ctx context.Context, initialBlockHistory uint
}

func (icp *IconChainProcessor) initializeConnectionState(ctx context.Context) error {
// TODO:
// TODO: review
ctx, cancel := context.WithTimeout(ctx, queryTimeout)
defer cancel()

Expand Down Expand Up @@ -218,6 +227,7 @@ func (icp *IconChainProcessor) GetLatestHeight() uint64 {
return icp.latestBlock.Height
}

// TODO: review add verifier
func (icp *IconChainProcessor) monitoring(ctx context.Context, persistence *queryCyclePersistence) error {

errCh := make(chan error) // error channel
Expand Down Expand Up @@ -294,11 +304,20 @@ loop:
}(ctxMonitorBlock, cancelMonitorBlock)
case br := <-btpBlockRespCh:
for ; br != nil; processedheight++ {
icp.latestBlockMu.Lock()
// verify BTP Block
err := icp.verifyBlock(ctx, br.Header)
if err != nil {
reconnect()
icp.log.Warn("failed to Verify BTP Block",
zap.Int64("got", br.Height),
zap.Error(err),
)
break
}

icp.latestBlock = provider.LatestBlock{
Height: uint64(processedheight),
}
icp.latestBlockMu.Unlock()

ibcMessage := parseIBCMessagesFromEventlog(icp.log, br.EventLogs, uint64(br.Height))
ibcMessageCache := processor.NewIBCMessagesCache()
Expand All @@ -311,16 +330,22 @@ loop:
icp.log.Info("Queried Latest height: ",
zap.String("chain id ", icp.chainProvider.ChainId()),
zap.Int64("height", br.Height))
err := icp.handlePathProcessorUpdate(ctx, br.Header, ibcMessageCache, ibcHeaderCache)
err = icp.handlePathProcessorUpdate(ctx, br.Header, ibcMessageCache, ibcHeaderCache)
if err != nil {
reconnect()
icp.log.Warn("Reconnect: error occured during handle block response ",
zap.Int64("got", br.Height),
)
break
}

// TODO: this is temporary adjustment
// if icp.firstTime {
// time.Sleep(4000 * time.Millisecond)
// } else {
// time.Sleep(100 * time.Millisecond)
// }
icp.firstTime = false
time.Sleep(100 * time.Millisecond)
if br = nil; len(btpBlockRespCh) > 0 {
br = <-btpBlockRespCh
}
Expand All @@ -338,11 +363,6 @@ loop:
for i := int64(0); bn != nil; i++ {
height, err := bn.Height.Value()

// icp.log.Info("for loop when receiving blockNotification",
// zap.Int64("height", height),
// zap.Int64("index", i),
// zap.Int64("processedheight", processedheight))

if err != nil {
return err
} else if height != processedheight+i {
Expand Down Expand Up @@ -419,6 +439,64 @@ loop:
}
}

func (icp *IconChainProcessor) verifyBlock(ctx context.Context, ibcHeader provider.IBCHeader) error {
header, ok := ibcHeader.(IconIBCHeader)
if !ok {
return fmt.Errorf("Provided Header is not compatible with IBCHeader")
}
if icp.firstTime {
proofContext, err := icp.chainProvider.GetProofContextByHeight(int64(header.MainHeight) - 1)
if err != nil {
return err
}
icp.verifier = &Verifier{
nextProofContext: proofContext,
verifiedHeight: int64(header.MainHeight) - 1,
}
}

if !ibcHeader.IsCompleteBlock() {
icp.verifier.nextProofContext = header.Validators
icp.verifier.verifiedHeight = int64(header.Height())
return nil
}

// prevNetworkSectionHash would be nil for first block
if icp.verifier.prevNetworkSectionHash != nil &&
!bytes.Equal(icp.verifier.prevNetworkSectionHash, header.Header.PrevNetworkSectionHash) {
return fmt.Errorf("failed to match prevNetworkSectionHash")
}

sigs, err := icp.chainProvider.GetBTPProof(int64(header.MainHeight))
if err != nil {
return err
}

decision := types.NewNetworkTypeSectionDecision(
getSrcNetworkId(icp.chainProvider.PCfg.ICONNetworkID),
icp.chainProvider.PCfg.BTPNetworkTypeID,
int64(header.MainHeight),
header.Header.Round,
types.NetworkTypeSection{
NextProofContextHash: header.Header.NextProofContextHash,
NetworkSectionsRoot: GetNetworkSectionRoot(header.Header),
})

valid, err := VerifyBtpProof(decision, sigs, icp.verifier.nextProofContext)
if err != nil {
return err
}

if !valid {
return fmt.Errorf("failed to Verify block")
}

icp.verifier.nextProofContext = header.Validators
icp.verifier.verifiedHeight = int64(header.Height())
icp.verifier.prevNetworkSectionHash = types.NewNetworkSection(header.Header).Hash()
return nil
}

func (icp *IconChainProcessor) handleBTPBlockRequest(
request *btpBlockRequest, requestCh chan *btpBlockRequest) {
defer func() {
Expand Down Expand Up @@ -563,9 +641,9 @@ func (icp *IconChainProcessor) handlePathProcessorUpdate(ctx context.Context,
// clientState will return the most recent client state if client messages
// have already been observed for the clientID, otherwise it will query for it.
func (icp *IconChainProcessor) clientState(ctx context.Context, clientID string) (provider.ClientState, error) {
// if state, ok := icp.latestClientState[clientID]; ok {
// return state, nil
// }
if state, ok := icp.latestClientState[clientID]; ok {
return state, nil
}
cs, err := icp.chainProvider.QueryClientStateWithoutProof(ctx, int64(icp.latestBlock.Height), clientID)
if err != nil {
return provider.ClientState{}, err
Expand Down
4 changes: 4 additions & 0 deletions relayer/chains/icon/module/app_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry)
(*MerkleProofState)(nil),
&icon.MerkleProofs{},
)
registry.RegisterImplementations(
(*exported.ClientMessage)(nil),
&icon.SignedHeader{},
)

}

Expand Down
50 changes: 39 additions & 11 deletions relayer/chains/icon/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func GetMockIconProvider(network_id int, contractAddress string) *IconProvider {
BTPNetworkTypeID: 1,
IbcHandlerAddress: contractAddress,
RPCAddr: "http://localhost:9082/api/v3",
// RPCAddr: "http://localhost:9999",
// RPCAddr: "https://berlin.net.solidwallet.io/api/v3",
Timeout: "20s",
}
log, _ := zap.NewProduction()
Expand Down Expand Up @@ -431,13 +431,41 @@ func TestHash(t *testing.T) {
// assert.Equal(common.Sha3keccak256(b))
}

// goloop rpc sendtx call \
// --uri http://localhost:9082/api/v3 \
// --nid 3 \
// --step_limit 1000000000\
// --to cxc3c1f693b1616860d9f709d9c85b5f613ea2dbdb \
// --method sendCallMessage \
// --param _to=eth \
// --param _data=0x6e696c696e \
// --key_store /Users/viveksharmapoudel/keystore/godWallet.json \
// --key_password gochain
// func TestUpdateClientHeader(t *testing.T) {

// p := GetMockIconProvider(2, "dddd")

// height := int64(401)
// header, _ := p.GetBtpHeader(height)
// proofContext, _ := p.GetProofContextByHeight(height - 1)

// cs, _ := p.MsgUpdateClientHeader(NewIconIBCHeader(header, proofContext, height), clienttypes.Height{}, nil)

// signedHeader, ok := cs.(*icon.SignedHeader)
// assert.True(t, ok)

// btpLocalHeader := types.BTPBlockHeader{
// MainHeight: signedHeader.Header.MainHeight,
// Round: int32(signedHeader.Header.Round),
// NextProofContextHash: signedHeader.Header.NextProofContextHash,
// NetworkSectionToRoot: signedHeader.Header.NetworkSectionToRoot,
// NetworkID: signedHeader.Header.NetworkId,
// UpdateNumber: header.UpdateNumber,
// PrevNetworkSectionHash: signedHeader.Header.PrevNetworkSectionHash,
// MessageCount: signedHeader.Header.MessageCount,
// MessageRoot: signedHeader.Header.MessageRoot,
// // NextProofContext: signedHeader.Header.NextProofContext,
// }
// networkSection := types.NewNetworkSection(&btpLocalHeader)
// fmt.Printf("newtworkSection :%x \n", networkSection.Hash())
// decision := types.NewNetworkTypeSectionDecision(getSrcNetworkId(3), 1, height, btpLocalHeader.Round,
// types.NetworkTypeSection{
// NextProofContextHash: btpLocalHeader.NextProofContextHash,
// NetworkSectionsRoot: GetNetworkSectionRoot(&btpLocalHeader),
// })

// isValid, err := VerifyBtpProof(decision, signedHeader.Signatures, proofContext)
// assert.NoError(t, err)

// assert.True(t, isValid)
// }
54 changes: 1 addition & 53 deletions relayer/chains/icon/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -548,59 +548,6 @@ func (icp *IconProvider) MsgUpdateClient(clientID string, counterpartyHeader ibc
return icp.NewIconMessage(updateClientMsg, MethodUpdateClient), nil
}

// func (icp *IconProvider) SendMessageIcon(ctx context.Context, msg provider.RelayerMessage) (*types.TransactionResult, bool, error) {
// m := msg.(*IconMessage)
// txParam := &types.TransactionParam{
// Version: types.NewHexInt(types.JsonrpcApiVersion),
// FromAddress: types.Address(icp.wallet.Address().String()),
// ToAddress: types.Address(icp.PCfg.IbcHandlerAddress),
// NetworkID: types.NewHexInt(icp.PCfg.ICONNetworkID),
// StepLimit: types.NewHexInt(int64(defaultStepLimit)),
// DataType: "call",
// Data: types.CallData{
// Method: m.Method,
// Params: m.Params,
// },
// }

// if err := icp.client.SignTransaction(icp.wallet, txParam); err != nil {
// return nil, false, err
// }
// _, err := icp.client.SendTransaction(txParam)
// if err != nil {
// return nil, false, err
// }

// txhash, _ := txParam.TxHash.Value()

// icp.log.Info("Submitted Transaction ", zap.String("chain Id ", icp.ChainId()),
// zap.String("method", m.Method), zap.String("txHash", fmt.Sprintf("0x%x", txhash)))

// txResParams := &types.TransactionHashParam{
// Hash: txParam.TxHash,
// }

// time.Sleep(2 * time.Second)

// txResult, err := icp.client.GetTransactionResult(txResParams)

// if err != nil {
// return nil, false, err
// }

// if txResult.Status != types.NewHexInt(1) {
// return nil, false, fmt.Errorf("Transaction Failed and the transaction Result is 0x%x", txhash)
// }

// icp.log.Info("Successful Transaction",
// zap.String("chain Id ", icp.ChainId()),
// zap.String("method", m.Method),
// zap.String("Height", string(txResult.BlockHeight)),
// zap.String("txHash", fmt.Sprintf("0x%x", txhash)))

// return txResult, true, err
// }

func (icp *IconProvider) SendMessage(ctx context.Context, msg provider.RelayerMessage, memo string) (*provider.RelayerTxResponse, bool, error) {

var (
Expand Down Expand Up @@ -783,6 +730,7 @@ func (icp *IconProvider) SendIconTransaction(
return nil
}

// TODO: review try to remove wait for Tx from packet-transfer and only use this for client and connection creation
func (icp *IconProvider) WaitForTxResult(
asyncCtx context.Context,
txHash []byte,
Expand Down
Loading