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

feat: add verifier for icon. #105

Merged
merged 9 commits into from
Jul 19, 2023
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 @@
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) queryCycle(ctx context.Context, persistence *queryCyclePersistence) error {
// TODO : review if redundent remove

Check warning on line 309 in relayer/chains/archway/archway_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/archway/archway_chain_processor.go#L309

Added line #L309 was not covered by tests
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 @@

chainID := ccp.chainProvider.ChainId()

// TODO review: max block sync
//

Check warning on line 361 in relayer/chains/archway/archway_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/archway/archway_chain_processor.go#L360-L361

Added lines #L360 - L361 were not covered by tests
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 @@
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 @@
packetData := event.Indexed[1]
var packet icon.Packet
if err := proto.Unmarshal(packetData, &packet); err != nil {

Check warning on line 35 in relayer/chains/icon/event_parser.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/event_parser.go#L35

Added line #L35 was not covered by tests
log.Error("failed to unmarshal packet")
// TODO: review return if parseAttrs add panic

Check warning on line 37 in relayer/chains/icon/event_parser.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/event_parser.go#L37

Added line #L37 was not covered by tests
}
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 @@

// 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) initializeConnectionState(ctx context.Context) error {
// TODO:
// TODO: review

Check warning on line 156 in relayer/chains/icon/icon_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/icon_chain_processor.go#L156

Added line #L156 was not covered by tests
ctx, cancel := context.WithTimeout(ctx, queryTimeout)
defer cancel()

Expand Down Expand Up @@ -218,6 +227,7 @@
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 @@
}(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

Check warning on line 315 in relayer/chains/icon/icon_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/icon_chain_processor.go#L307-L315

Added lines #L307 - L315 were not covered by tests
}

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 @@
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)

Check warning on line 333 in relayer/chains/icon/icon_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/icon_chain_processor.go#L333

Added line #L333 was not covered by tests
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 @@
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 @@
}
}

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,
}

Check warning on line 455 in relayer/chains/icon/icon_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/icon_chain_processor.go#L442-L455

Added lines #L442 - L455 were not covered by tests
}

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

Check warning on line 462 in relayer/chains/icon/icon_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/icon_chain_processor.go#L458-L462

Added lines #L458 - L462 were not covered by tests

// 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")
}

Check warning on line 468 in relayer/chains/icon/icon_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/icon_chain_processor.go#L465-L468

Added lines #L465 - L468 were not covered by tests

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

Check warning on line 473 in relayer/chains/icon/icon_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/icon_chain_processor.go#L470-L473

Added lines #L470 - L473 were not covered by tests

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
}

Check warning on line 488 in relayer/chains/icon/icon_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/icon_chain_processor.go#L475-L488

Added lines #L475 - L488 were not covered by tests

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

Check warning on line 492 in relayer/chains/icon/icon_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/icon_chain_processor.go#L490-L492

Added lines #L490 - L492 were not covered by tests

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

Check warning on line 497 in relayer/chains/icon/icon_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/icon_chain_processor.go#L494-L497

Added lines #L494 - L497 were not covered by tests
}

func (icp *IconChainProcessor) handleBTPBlockRequest(
request *btpBlockRequest, requestCh chan *btpBlockRequest) {
defer func() {
Expand Down Expand Up @@ -563,9 +641,9 @@
// 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
}

Check warning on line 646 in relayer/chains/icon/icon_chain_processor.go

View check run for this annotation

Codecov / codecov/patch

relayer/chains/icon/icon_chain_processor.go#L644-L646

Added lines #L644 - L646 were not covered by tests
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
Loading