Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ docker/payload
config.json
peers.recent
.vscode
poly
16 changes: 10 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.14

require (
github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20210329093354-1b8e0a7a2e25
github.com/btcsuite/btcd v0.20.1-beta
github.com/btcsuite/btcd v0.21.0-beta
github.com/btcsuite/btcutil v1.0.2
github.com/cosmos/cosmos-sdk v0.39.1
github.com/ethereum/go-ethereum v1.9.15
Expand All @@ -15,18 +15,22 @@ require (
github.com/hashicorp/golang-lru v0.5.4
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c
github.com/itchyny/base58-go v0.1.0
github.com/joeqian10/neo-gogogo v0.0.0-20200716075409-923bd4879b43
github.com/joeqian10/neo-gogogo v1.1.0
github.com/joeqian10/neo3-gogogo v0.3.3
github.com/kardiachain/go-kaiclient v1.0.2-0.20210525090440-5f0648f4d185 // indirect
github.com/kardiachain/go-kardia v1.2.3-0.20210525082104-2913103edf92 // indirect
github.com/ontio/ontology v1.11.1-0.20200812075204-26cf1fa5dd47
github.com/ontio/ontology-crypto v1.0.9
github.com/ontio/ontology-eventbus v0.9.1
github.com/pborman/uuid v1.2.0
github.com/polynetwork/poly-io-test v0.0.0-20200819093740-8cf514b07750
github.com/stretchr/testify v1.6.1
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d
github.com/prometheus/tsdb v0.10.0 // indirect
github.com/stretchr/testify v1.7.0
github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca
github.com/tendermint/tendermint v0.33.7
github.com/urfave/cli v1.22.4
github.com/valyala/bytebufferpool v1.0.0
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
golang.org/x/net v0.0.0-20200822124328-c89045814202
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
gotest.tools v2.2.0+incompatible
)
106 changes: 106 additions & 0 deletions go.sum

Large diffs are not rendered by default.

Binary file added merkle/merkletree.db
Binary file not shown.
6 changes: 6 additions & 0 deletions native/service/cross_chain_manager/entrance.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ import (
"github.com/polynetwork/poly/native/service/cross_chain_manager/cosmos"
"github.com/polynetwork/poly/native/service/cross_chain_manager/eth"
"github.com/polynetwork/poly/native/service/cross_chain_manager/heco"
"github.com/polynetwork/poly/native/service/cross_chain_manager/kai"
"github.com/polynetwork/poly/native/service/cross_chain_manager/msc"
"github.com/polynetwork/poly/native/service/cross_chain_manager/neo"
"github.com/polynetwork/poly/native/service/cross_chain_manager/neo3"
"github.com/polynetwork/poly/native/service/cross_chain_manager/okex"
"github.com/polynetwork/poly/native/service/cross_chain_manager/ont"
"github.com/polynetwork/poly/native/service/cross_chain_manager/quorum"
Expand Down Expand Up @@ -66,6 +68,8 @@ func GetChainHandler(router uint64) (scom.ChainHandler, error) {
return ont.NewONTHandler(), nil
case utils.NEO_ROUTER:
return neo.NewNEOHandler(), nil
case utils.NEO3_ROUTER:
return neo3.NewNeo3Handler(), nil
case utils.COSMOS_ROUTER:
return cosmos.NewCosmosHandler(), nil
case utils.QUORUM_ROUTER:
Expand All @@ -80,6 +84,8 @@ func GetChainHandler(router uint64) (scom.ChainHandler, error) {
return msc.NewHandler(), nil
case utils.OKEX_ROUTER:
return okex.NewHandler(), nil
case utils.KAI_ROUTER:
return kai.NewHandler(), nil
default:
return nil, fmt.Errorf("not a supported router:%d", router)
}
Expand Down
261 changes: 261 additions & 0 deletions native/service/cross_chain_manager/kai/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
/*
* Copyright (C) 2020 The poly network Authors
* This file is part of The poly network library.
*
* The poly network 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 poly network 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 poly network . If not, see <http://www.gnu.org/licenses/>.
*/

package kai

import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"math/big"

ecommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
kaiclient "github.com/kardiachain/go-kaiclient/kardia"
"github.com/kardiachain/go-kardia/types"
"github.com/polynetwork/poly/common"
"github.com/polynetwork/poly/common/log"
"github.com/polynetwork/poly/native"
scom "github.com/polynetwork/poly/native/service/cross_chain_manager/common"
"github.com/polynetwork/poly/native/service/governance/side_chain_manager"
hskai "github.com/polynetwork/poly/native/service/header_sync/kai"
)

// Handler ...
type Handler struct {
}

// NewHandler ...
func NewHandler() *Handler {
return &Handler{}
}

// MakeDepositProposal ...
func (h *Handler) MakeDepositProposal(service *native.NativeService) (*scom.MakeTxParam, error) {
params := new(scom.EntranceParam)
if err := params.Deserialization(common.NewZeroCopySource(service.GetInput())); err != nil {
return nil, fmt.Errorf("KAI MakeDepositProposal, contract params deserialize error: %s", err)
}
info, err := hskai.GetEpochSwitchInfo(service, params.SourceChainID)
if err != nil {
return nil, fmt.Errorf("KAI MakeDepositProposal, failed to get epoch switching height: %v", err)
}
if info.Height > int64(params.Height) {
return nil, fmt.Errorf("KAI MakeDepositProposal, the height %d of header is lower than epoch "+
"switching height %d", params.Height, info.Height)
}

if len(params.HeaderOrCrossChainMsg) == 0 {
return nil, fmt.Errorf("you must commit the header used to verify transaction's proof and get none")
}

var myHeader kaiclient.FullHeader
if err := json.Unmarshal(params.HeaderOrCrossChainMsg, &myHeader); err != nil {
return nil, fmt.Errorf("KAI MakeDepositProposal, unmarshal cosmos header failed: %v", err)
}
if myHeader.Header.Height != uint64(params.Height) {
return nil, fmt.Errorf("KAI MakeDepositProposal, "+
"height of your header is %d not equal to %d in parameter", myHeader.Header.Height, params.Height)
}

if err = hskai.VerifyHeader(&myHeader, info); err != nil {
return nil, fmt.Errorf("KAI MakeDepositProposal, failed to verify KAI header: %v", err)
}

sideChain, err := side_chain_manager.GetSideChain(service, params.SourceChainID)
if err != nil {
return nil, fmt.Errorf("KAI MakeDepositProposal, side_chain_manager.GetSideChain error: %v", err)
}

if !myHeader.Header.ValidatorsHash.Equal(myHeader.Header.NextValidatorsHash) &&
int64(myHeader.Header.Height) > info.Height {
hskai.PutEpochSwitchInfo(service, params.SourceChainID, &hskai.EpochSwitchInfo{
Height: int64(myHeader.Header.Height),
BlockHash: myHeader.Header.Hash().Bytes(),
NextValidatorsHash: myHeader.Header.NextValidatorsHash.Bytes(),
ChainID: info.ChainID,
})
}

value, err := verifyTx(myHeader.Header, service, params.Proof, params.Extra, params.SourceChainID, params.Height, sideChain)
if err != nil {
return nil, fmt.Errorf("KAI MakeDepositProposal, verifyFromEthTx error: %s", err)
}

if err := scom.CheckDoneTx(service, value.CrossChainID, params.SourceChainID); err != nil {
return nil, fmt.Errorf("KAI MakeDepositProposal, check done transaction error:%s", err)
}
if err := scom.PutDoneTx(service, value.CrossChainID, params.SourceChainID); err != nil {
return nil, fmt.Errorf("KAI MakeDepositProposal, PutDoneTx error:%s", err)
}

return nil, nil
}

func verifyTx(header *types.Header, native *native.NativeService, proof, extra []byte, fromChainID uint64, height uint32, sideChain *side_chain_manager.SideChain) (param *scom.MakeTxParam, err error) {
kaiProof := new(Proof)
err = json.Unmarshal(proof, kaiProof)
if err != nil {
return nil, fmt.Errorf("verifyTx, unmarshal proof error:%s", err)
}

if len(kaiProof.StorageProofs) != 1 {
return nil, fmt.Errorf("verifyTx, incorrect proof format")
}

proofResult, err := verifyMerkleProof(kaiProof, header, sideChain.CCMCAddress)
if err != nil {
return nil, fmt.Errorf("verifyTx, verifyMerkleProof error:%v", err)
}

if proofResult == nil {
return nil, fmt.Errorf("verifyTx, verifyMerkleProof failed")
}

if !checkProofResult(proofResult, extra) {
return nil, fmt.Errorf("verifyTx, verify proof value hash failed, proof result:%x, extra:%x", proofResult, extra)
}

data := common.NewZeroCopySource(extra)
txParam := new(scom.MakeTxParam)
if err := txParam.Deserialization(data); err != nil {
return nil, fmt.Errorf("verifyTx, deserialize merkleValue error:%s", err)
}
return txParam, nil
}

// Proof ...
type Proof struct {
Address string `json:"address"`
Balance string `json:"balance"`
CodeHash string `json:"codeHash"`
Nonce string `json:"nonce"`
StorageHash string `json:"storageHash"`
AccountProof []string `json:"accountProof"`
StorageProofs []StorageProof `json:"storageProof"`
}

// StorageProof ...
type StorageProof struct {
Key string `json:"key"`
Value string `json:"value"`
Proof []string `json:"proof"`
}

// ProofAccount ...
type ProofAccount struct {
Nounce *big.Int
Balance *big.Int
Storage ecommon.Hash
Codehash ecommon.Hash
}

func verifyMerkleProof(kaiProof *Proof, blockData *types.Header, contractAddr []byte) ([]byte, error) {
//1. prepare verify account
nodeList := new(light.NodeList)

for _, s := range kaiProof.AccountProof {
p := scom.Replace0x(s)
nodeList.Put(nil, ecommon.Hex2Bytes(p))
}
ns := nodeList.NodeSet()

addr := ecommon.Hex2Bytes(scom.Replace0x(kaiProof.Address))
if !bytes.Equal(addr, contractAddr) {
return nil, fmt.Errorf("verifyMerkleProof, contract address is error, proof address: %s, side chain address: %s", kaiProof.Address, hex.EncodeToString(contractAddr))
}
acctKey := crypto.Keccak256(addr)

//2. verify account proof
acctVal, err := trie.VerifyProof(ecommon.Hash(blockData.AppHash), acctKey, ns)
if err != nil {
return nil, fmt.Errorf("verifyMerkleProof, verify account proof error:%s", err)
}

nounce := new(big.Int)
_, ok := nounce.SetString(scom.Replace0x(kaiProof.Nonce), 16)
if !ok {
return nil, fmt.Errorf("verifyMerkleProof, invalid format of nounce:%s", kaiProof.Nonce)
}

balance := new(big.Int)
_, ok = balance.SetString(scom.Replace0x(kaiProof.Balance), 16)
if !ok {
return nil, fmt.Errorf("verifyMerkleProof, invalid format of balance:%s", kaiProof.Balance)
}

storageHash := ecommon.HexToHash(scom.Replace0x(kaiProof.StorageHash))
codeHash := ecommon.HexToHash(scom.Replace0x(kaiProof.CodeHash))

acct := &ProofAccount{
Nounce: nounce,
Balance: balance,
Storage: storageHash,
Codehash: codeHash,
}

acctrlp, err := rlp.EncodeToBytes(acct)
if err != nil {
return nil, err
}

if !bytes.Equal(acctrlp, acctVal) {
return nil, fmt.Errorf("verifyMerkleProof, verify account proof failed, wanted:%v, get:%v", acctrlp, acctVal)
}

//3.verify storage proof
nodeList = new(light.NodeList)
if len(kaiProof.StorageProofs) != 1 {
return nil, fmt.Errorf("verifyMerkleProof, invalid storage proof format")
}

sp := kaiProof.StorageProofs[0]
storageKey := crypto.Keccak256(ecommon.HexToHash(scom.Replace0x(sp.Key)).Bytes())

for _, prf := range sp.Proof {
nodeList.Put(nil, ecommon.Hex2Bytes(scom.Replace0x(prf)))
}

ns = nodeList.NodeSet()
val, err := trie.VerifyProof(storageHash, storageKey, ns)
if err != nil {
return nil, fmt.Errorf("verifyMerkleProof, verify storage proof error:%s", err)
}

return val, nil
}

func checkProofResult(result, value []byte) bool {
var tempBytes []byte
err := rlp.DecodeBytes(result, &tempBytes)
if err != nil {
log.Errorf("checkProofResult, rlp.DecodeBytes error:%s\n", err)
return false
}
//
var s []byte
for i := len(tempBytes); i < 32; i++ {
s = append(s, 0)
}
s = append(s, tempBytes...)
hash := crypto.Keccak256(value)
return bytes.Equal(s, hash)
}
46 changes: 46 additions & 0 deletions native/service/cross_chain_manager/kai/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package kai

import (
"encoding/hex"
"fmt"
"testing"

"github.com/polynetwork/poly/common"
cstates "github.com/polynetwork/poly/core/states"
"github.com/polynetwork/poly/core/store/leveldbstore"
"github.com/polynetwork/poly/core/store/overlaydb"
"github.com/polynetwork/poly/core/types"
"github.com/polynetwork/poly/native"
"github.com/polynetwork/poly/native/service/governance/side_chain_manager"
"github.com/polynetwork/poly/native/service/utils"
"github.com/polynetwork/poly/native/storage"
)

func NewNative(args []byte, tx *types.Transaction, db *storage.CacheDB) *native.NativeService {
if db == nil {
store, _ := leveldbstore.NewMemLevelDBStore()
db = storage.NewCacheDB(overlaydb.NewOverlayDB(store))
}
ns, err := native.NewNativeService(db, tx, 0, 0, common.Uint256{0}, 0, args, false)
if err != nil {
panic(fmt.Errorf("NewNativeService error: %+v", err))
}

contaractAddr, _ := hex.DecodeString("48A77F43C0D7A6D6f588c4758dbA22bf6C5D95a0")
side := &side_chain_manager.SideChain{
Name: "kai",
ChainId: 138,
BlocksToWait: 1,
Router: 1,
CCMCAddress: contaractAddr,
}
sink := common.NewZeroCopySink(nil)
_ = side.Serialization(sink)
ns.GetCacheDB().Put(utils.ConcatKey(utils.SideChainManagerContractAddress, []byte(side_chain_manager.SIDE_CHAIN), utils.GetUint64Bytes(2)), cstates.GenRawStorageItem(sink.Bytes()))
return ns
}

func TestMakeDepositProposal(t *testing.T) {
//handler := NewHandler()

}
4 changes: 2 additions & 2 deletions native/service/cross_chain_manager/neo/neo_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ func (this *NEOHandler) MakeDepositProposal(service *native.NativeService) (*sco
}
// Ensure the tx has not been processed before, and mark the tx as processed
if err := scom.CheckDoneTx(service, value.CrossChainID, params.SourceChainID); err != nil {
return nil, fmt.Errorf("neo MakeDepositProposal, check done transaction error:%s", err)
return nil, fmt.Errorf("neo MakeDepositProposal, check done transaction error: %s", err)
}
if err = scom.PutDoneTx(service, value.CrossChainID, params.SourceChainID); err != nil {
return nil, fmt.Errorf("neo MakeDepositProposal, putDoneTx error:%s", err)
return nil, fmt.Errorf("neo MakeDepositProposal, putDoneTx error: %s", err)
}
return value, nil
}
Loading