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
6be4410
add support for Neo N3
joeqian10 Apr 16, 2021
4cd36cb
fix typo
joeqian10 Apr 16, 2021
ca4d9ca
add neo2 back
joeqian10 Apr 16, 2021
067ba90
fix neo3 header deserialization, rename structs
joeqian10 Apr 21, 2021
9a36e38
fix
joeqian10 Apr 21, 2021
4f959cc
fix 2
joeqian10 Apr 21, 2021
437aa38
fix neoCrossChainMsg
joeqian10 Apr 29, 2021
474879d
add neo3 state validator manager
joeqian10 May 13, 2021
7c006f5
add support native kai
dogecoindev May 17, 2021
a187e36
remove db
dogecoindev May 17, 2021
6be8177
add kai router
dogecoindev May 17, 2021
d2d6694
update import go-eth version
dogecoindev May 18, 2021
4034bfb
update neo3 state root GetMessage()
joeqian10 May 18, 2021
4f8d44e
Merge branch 'master' into master
joeqian10 May 18, 2021
24b1d3d
get neo3 magic from side chain extra info
joeqian10 May 18, 2021
22bce4f
Merge branch 'master' of https://github.com/joeqian10/poly
joeqian10 May 18, 2021
c36d24c
update dependency
joeqian10 May 19, 2021
24ddfe9
remove merkletree.db
dogecoindev May 20, 2021
733e4e0
remove unused code
joeqian10 May 20, 2021
ebead48
discard map for filtering
joeqian10 May 21, 2021
7079ecb
Merge https://github.com/joeqian10/poly into kai
dogecoindev May 21, 2021
efaaf7f
Revert "remove merkletree.db"
dogecoindev May 21, 2021
b1937a3
fix register kai handler
dogecoindev May 21, 2021
39aec30
add unitest kai header sync
dogecoindev May 25, 2021
9446cd3
update unitest
dogecoindev May 25, 2021
48907b9
fix import kai full header
dogecoindev May 25, 2021
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