diff --git a/contracts/native/cross_chain_manager/cosmos/cosmos_handler.go b/contracts/native/cross_chain_manager/cosmos/cosmos_handler.go index bf974674..57323646 100644 --- a/contracts/native/cross_chain_manager/cosmos/cosmos_handler.go +++ b/contracts/native/cross_chain_manager/cosmos/cosmos_handler.go @@ -19,6 +19,7 @@ package cosmos import ( "bytes" "fmt" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/rootmulti" "github.com/ethereum/go-ethereum/contracts/native" @@ -88,7 +89,7 @@ func (this *CosmosHandler) MakeDepositProposal(service *native.NativeContract) ( return nil, fmt.Errorf("Cosmos MakeDepositProposal, failed to verify cosmos header: %v", err) } if !bytes.Equal(myHeader.Header.ValidatorsHash, myHeader.Header.NextValidatorsHash) && - uint64(myHeader.Header.Height) > info.Height { + myHeader.Header.Height > 0 && uint64(myHeader.Header.Height) > info.Height { if err := cosmos.PutEpochSwitchInfo(service, params.SourceChainID, &cosmos.CosmosEpochSwitchInfo{ Height: uint64(myHeader.Header.Height), BlockHash: myHeader.Header.Hash(), diff --git a/contracts/native/cross_chain_manager/okex/okex_handler.go b/contracts/native/cross_chain_manager/okex/okex_handler.go index 9e8b91b6..283786b9 100644 --- a/contracts/native/cross_chain_manager/okex/okex_handler.go +++ b/contracts/native/cross_chain_manager/okex/okex_handler.go @@ -56,7 +56,7 @@ func (this *OKHandler) MakeDepositProposal(service *native.NativeContract) (*sco if err != nil { return nil, fmt.Errorf("okex MakeDepositProposal, failed to get epoch switching height: %v", err) } - if info.Height > int64(params.Height) { + if info.Height > uint64(params.Height) { return nil, fmt.Errorf("okex MakeDepositProposal, the height %d of header is lower than epoch "+ "switching height %d", params.Height, info.Height) } @@ -77,13 +77,15 @@ func (this *OKHandler) MakeDepositProposal(service *native.NativeContract) (*sco return nil, fmt.Errorf("okex MakeDepositProposal, failed to verify okex header: %v", err) } if !bytes.Equal(myHeader.Header.ValidatorsHash, myHeader.Header.NextValidatorsHash) && - myHeader.Header.Height > info.Height { - okex.PutEpochSwitchInfo(service, params.SourceChainID, &okex.CosmosEpochSwitchInfo{ - Height: myHeader.Header.Height, + myHeader.Header.Height > 0 && uint64(myHeader.Header.Height) > info.Height { + if err := okex.PutEpochSwitchInfo(service, params.SourceChainID, &okex.CosmosEpochSwitchInfo{ + Height: uint64(myHeader.Header.Height), BlockHash: myHeader.Header.Hash(), NextValidatorsHash: myHeader.Header.NextValidatorsHash, ChainID: myHeader.Header.ChainID, - }) + }); err != nil { + return nil, fmt.Errorf("okex MakeDepositProposal, failed to PutEpochSwitchInfo: %v", err) + } } var proofValue CosmosProofValue diff --git a/contracts/native/header_sync/cosmos/header_sync.go b/contracts/native/header_sync/cosmos/header_sync.go index d69d8792..b0d38fbf 100644 --- a/contracts/native/header_sync/cosmos/header_sync.go +++ b/contracts/native/header_sync/cosmos/header_sync.go @@ -81,6 +81,10 @@ func (this *CosmosHandler) SyncGenesisHeader(native *native.NativeContract) erro if err == nil && info != nil { return fmt.Errorf("CosmosHandler SyncGenesisHeader, genesis header had been initialized") } + // prevent that header height will be converted from negative to positive + if header.Header.Height < 0 { + return fmt.Errorf("CosmosHandler SyncGenesisHeader: %s", "header height invalid") + } if err := PutEpochSwitchInfo(native, param.ChainID, &CosmosEpochSwitchInfo{ Height: uint64(header.Header.Height), NextValidatorsHash: header.Header.NextValidatorsHash, @@ -115,6 +119,10 @@ func (this *CosmosHandler) SyncBlockHeader(native *native.NativeContract) error if bytes.Equal(myHeader.Header.NextValidatorsHash, myHeader.Header.ValidatorsHash) { continue } + // prevent that header height will be converted from negative to positive + if myHeader.Header.Height < 0 { + return fmt.Errorf("SyncBlockHeader, header height invalid") + } if info.Height >= uint64(myHeader.Header.Height) { log.Debugf("SyncBlockHeader, height %d is lower or equal than epoch switching height %d", myHeader.Header.Height, info.Height) diff --git a/contracts/native/header_sync/okex/header_sync.go b/contracts/native/header_sync/okex/header_sync.go index d7d047ab..2765bdcc 100644 --- a/contracts/native/header_sync/okex/header_sync.go +++ b/contracts/native/header_sync/okex/header_sync.go @@ -86,8 +86,12 @@ func (h *Handler) SyncGenesisHeader(native *native.NativeContract) (err error) { if err == nil && info != nil { return fmt.Errorf("CosmosHandler SyncGenesisHeader, genesis header had been initialized") } + // prevent that header height will be converted from negative to positive + if header.Header.Height < 0 { + return fmt.Errorf("CosmosHandler SyncGenesisHeader: %s", "header height invalid") + } if err := PutEpochSwitchInfo(native, param.ChainID, &CosmosEpochSwitchInfo{ - Height: header.Header.Height, + Height: uint64(header.Header.Height), NextValidatorsHash: header.Header.NextValidatorsHash, ChainID: header.Header.ChainID, BlockHash: header.Header.Hash(), @@ -121,7 +125,11 @@ func (h *Handler) SyncBlockHeader(native *native.NativeContract) error { if bytes.Equal(myHeader.Header.NextValidatorsHash, myHeader.Header.ValidatorsHash) { continue } - if info.Height >= myHeader.Header.Height { + // prevent that header height will be converted from negative to positive + if myHeader.Header.Height < 0 { + return fmt.Errorf("SyncBlockHeader, header height invalid") + } + if info.Height >= uint64(myHeader.Header.Height) { log.Debugf("SyncBlockHeader, height %d is lower or equal than epoch switching height %d", myHeader.Header.Height, info.Height) continue @@ -130,7 +138,7 @@ func (h *Handler) SyncBlockHeader(native *native.NativeContract) error { return fmt.Errorf("SyncBlockHeader, failed to verify header: %v", err) } info.NextValidatorsHash = myHeader.Header.NextValidatorsHash - info.Height = myHeader.Header.Height + info.Height = uint64(myHeader.Header.Height) info.BlockHash = myHeader.Header.Hash() cnt++ } @@ -173,14 +181,14 @@ func PutEpochSwitchInfo(service *native.NativeContract, chainId uint64, info *Co func notifyEpochSwitchInfo(native *native.NativeContract, chainID uint64, info *CosmosEpochSwitchInfo) error { return native.AddNotify(hscommon.ABI, []string{"OKEpochSwitchInfoEvent"}, chainID, info.BlockHash.String(), info.Height, - info.NextValidatorsHash.String(), info.ChainID, native.ContractRef().BlockHeight()) + info.NextValidatorsHash.String(), info.ChainID, native.ContractRef().BlockHeight().Uint64()) } type CosmosEpochSwitchInfo struct { // The height where validators set changed last time. Poly only accept // header and proof signed by new validators. That means the header // can not be lower than this height. - Height int64 + Height uint64 // Hash of the block at `Height`. Poly don't save the whole header. // So we can identify the content of this block by `BlockHash`. @@ -200,7 +208,7 @@ func (m *CosmosEpochSwitchInfo) EncodeRLP(w io.Writer) error { func (m *CosmosEpochSwitchInfo) DecodeRLP(s *rlp.Stream) error { var data struct { - Height int64 + Height uint64 BlockHash tbytes.HexBytes NextValidatorsHash tbytes.HexBytes ChainID string diff --git a/contracts/native/header_sync/okex/header_sync_test.go b/contracts/native/header_sync/okex/header_sync_test.go new file mode 100644 index 00000000..96b49662 --- /dev/null +++ b/contracts/native/header_sync/okex/header_sync_test.go @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 The Zion Authors + * This file is part of The Zion library. + * + * The Zion is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Zion is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The Zion. If not, see . + */ + +package okex + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/contracts/native" + hscommon "github.com/ethereum/go-ethereum/contracts/native/header_sync/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/rlp" + "github.com/stretchr/testify/assert" + "github.com/tendermint/tendermint/libs/bytes" +) + +func TestCosmosEpochSwitchInfo(t *testing.T) { + expect := &CosmosEpochSwitchInfo{ + Height: 12, + BlockHash: []byte{'1', '3', '5'}, + NextValidatorsHash: []byte{'2', '4', '6'}, + ChainID: "hahaha", + } + + blob, err := rlp.EncodeToBytes(expect) + assert.NoError(t, err) + + got := new(CosmosEpochSwitchInfo) + assert.NoError(t, rlp.DecodeBytes(blob, got)) + + assert.Equal(t, expect, got) +} + +func TestNotifyEpochChangeEvent(t *testing.T) { + hscommon.ABI = hscommon.GetABI() + + db := rawdb.NewMemoryDatabase() + sdb, _ := state.New(common.Hash{}, state.NewDatabase(db), nil) + ref := native.NewContractRef(sdb, common.Address{}, common.Address{}, big.NewInt(1), common.Hash{}, 0, nil) + ctx := native.NewNativeContract(sdb, ref) + ref.PushContext(&native.Context{ + Caller: common.Address{}, + ContractAddress: common.Address{}, + Payload: nil, + }) + + inf := &CosmosEpochSwitchInfo{ + Height: 321, + BlockHash: bytes.HexBytes{'1', '2'}, + NextValidatorsHash: bytes.HexBytes{'1', '2'}, + ChainID: "12", + } + + assert.NoError(t, notifyEpochSwitchInfo(ctx, 12, inf)) +} diff --git a/contracts/native/header_sync/polygon/heimdall_header_sync.go b/contracts/native/header_sync/polygon/heimdall_header_sync.go index d9b6b97d..eac3882d 100644 --- a/contracts/native/header_sync/polygon/heimdall_header_sync.go +++ b/contracts/native/header_sync/polygon/heimdall_header_sync.go @@ -75,8 +75,11 @@ func (h *HeimdallHandler) SyncGenesisHeader(native *native.NativeContract) (err if err == nil && info != nil { return fmt.Errorf("HeimdallHandler SyncGenesisHeader, genesis header had been initialized") } + if header.Header.Height < 0 { + return fmt.Errorf("HeidallHandler SyncGenesisHeader, header height invalid") + } if err := PutEpochSwitchInfo(native, param.ChainID, &CosmosEpochSwitchInfo{ - Height: header.Header.Height, + Height: uint64(header.Header.Height), NextValidatorsHash: header.Header.NextValidatorsHash, ChainID: header.Header.ChainID, BlockHash: header.Header.Hash(), @@ -110,7 +113,10 @@ func (h *HeimdallHandler) SyncBlockHeader(native *native.NativeContract) error { if bytes.Equal(myHeader.Header.NextValidatorsHash, myHeader.Header.ValidatorsHash) { continue } - if info.Height >= myHeader.Header.Height { + if myHeader.Header.Height < 0 { + return fmt.Errorf("SyncBlockHeader, header height invalid") + } + if info.Height >= uint64(myHeader.Header.Height) { log.Debugf("SyncBlockHeader, height %d is lower or equal than epoch switching height %d", myHeader.Header.Height, info.Height) continue @@ -119,7 +125,7 @@ func (h *HeimdallHandler) SyncBlockHeader(native *native.NativeContract) error { return fmt.Errorf("SyncBlockHeader, failed to verify header: %v", err) } info.NextValidatorsHash = myHeader.Header.NextValidatorsHash - info.Height = myHeader.Header.Height + info.Height = uint64(myHeader.Header.Height) info.BlockHash = myHeader.Header.Hash() cnt++ } @@ -166,7 +172,7 @@ type CosmosEpochSwitchInfo struct { // The height where validators set changed last time. Poly only accept // header and proof signed by new validators. That means the header // can not be lower than this height. - Height int64 + Height uint64 // Hash of the block at `Height`. Poly don't save the whole header. // So we can identify the content of this block by `BlockHash`. @@ -186,7 +192,7 @@ func (m *CosmosEpochSwitchInfo) EncodeRLP(w io.Writer) error { func (m *CosmosEpochSwitchInfo) DecodeRLP(s *rlp.Stream) error { var data struct { - Height int64 + Height uint64 BlockHash polygonCmn.HexBytes NextValidatorsHash polygonCmn.HexBytes ChainID string