diff --git a/native/service/cross_chain_manager/chainsql/chainsql_handler.go b/native/service/cross_chain_manager/chainsql/chainsql_handler.go new file mode 100644 index 00000000..e02b36e1 --- /dev/null +++ b/native/service/cross_chain_manager/chainsql/chainsql_handler.go @@ -0,0 +1,72 @@ +/* + * 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 . + */ +package chainsql + +import ( + "fmt" + pcom "github.com/polynetwork/poly/common" + "github.com/polynetwork/poly/native" + "github.com/polynetwork/poly/native/service/cross_chain_manager/common" + "github.com/polynetwork/poly/native/service/header_sync/chainsql" + hcom "github.com/polynetwork/poly/native/service/header_sync/common" +) + +type ChainsqlHandler struct{} + +func NewChainsqlHandler() *ChainsqlHandler { + return &ChainsqlHandler{} +} + +func (this *ChainsqlHandler) MakeDepositProposal(ns *native.NativeService) (*common.MakeTxParam, error) { + params := new(common.EntranceParam) + if err := params.Deserialization(pcom.NewZeroCopySource(ns.GetInput())); err != nil { + return nil, fmt.Errorf("Chainsql MakeDepositProposal, contract params deserialize error: %v", err) + } + val := &common.MakeTxParam{} + if err := val.Deserialization(pcom.NewZeroCopySource(params.Extra)); err != nil { + return nil, fmt.Errorf("Chainsql MakeDepositProposal, failed to deserialize MakeTxParam: %v", err) + } + if err := common.CheckDoneTx(ns, val.CrossChainID, params.SourceChainID); err != nil { + return nil, fmt.Errorf("Chainsql MakeDepositProposal, check done transaction error: %v", err) + } + if err := common.PutDoneTx(ns, val.CrossChainID, params.SourceChainID); err != nil { + return nil, fmt.Errorf("Chainsql MakeDepositProposal, PutDoneTx error: %v", err) + } + + root, err := chainsql.GetChainsqlRoot(ns, params.SourceChainID) + if err != nil { + return nil, fmt.Errorf("Chainsql MakeDepositProposal, failed to get the chainsql root cert: %v", err) + } + now := ns.GetBlockTime() + if now.After(root.RootCA.NotAfter) || now.Before(root.RootCA.NotBefore) { + return nil, fmt.Errorf("Chainsql MakeDepositProposal, Chainsql root CA need to update for chain %d: (start: %d, end: %d, block_time: %d)", + params.SourceChainID, root.RootCA.NotBefore.Unix(), root.RootCA.NotAfter.Unix(), now.Unix()) + } + certs := &hcom.CertTrustChain{} + if err := certs.Deserialization(pcom.NewZeroCopySource(params.HeaderOrCrossChainMsg)); err != nil { + return nil, fmt.Errorf("Chainsql MakeDepositProposal, failed to deserialize CertTrustChain: %v", err) + } + if err := certs.Validate(ns); err != nil { + return nil, fmt.Errorf("Chainsql MakeDepositProposal, validate not pass: %v", err) + } + if err := certs.CheckSigWithRootCert(root.RootCA, params.Extra, params.Proof); err != nil { + return nil, fmt.Errorf("Chainsql MakeDepositProposal, failed to check sig: %v", err) + } + PutChainsqlLatestHeightInProcessing(ns, params.SourceChainID, val.FromContractAddress, params.Height) + + return val, nil +} diff --git a/native/service/cross_chain_manager/chainsql/chainsql_handler_test.go b/native/service/cross_chain_manager/chainsql/chainsql_handler_test.go new file mode 100644 index 00000000..a4792a85 --- /dev/null +++ b/native/service/cross_chain_manager/chainsql/chainsql_handler_test.go @@ -0,0 +1,189 @@ +/* + * 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 . + */ +package chainsql + +import ( + "crypto/ecdsa" + "crypto/rand" + "encoding/pem" + "github.com/ontio/ontology-crypto/keypair" + "github.com/polynetwork/poly/account" + "github.com/polynetwork/poly/common" + "github.com/polynetwork/poly/consensus/vbft/config" + "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" + common2 "github.com/polynetwork/poly/native/service/cross_chain_manager/common" + "github.com/polynetwork/poly/native/service/governance/node_manager" + chainsql2 "github.com/polynetwork/poly/native/service/header_sync/chainsql" + common3 "github.com/polynetwork/poly/native/service/header_sync/common" + "github.com/polynetwork/poly/native/service/utils" + "github.com/polynetwork/poly/native/storage" + "github.com/tjfoc/gmsm/pkcs12" + "github.com/tjfoc/gmsm/sm2" + "gotest.tools/assert" + "testing" + "time" +) + +var ( + acct = account.NewAccount("") + + getNativeFunc = func(args []byte, db *storage.CacheDB, cert string) *native.NativeService { + if db == nil { + store, _ := leveldbstore.NewMemLevelDBStore() + db = storage.NewCacheDB(overlaydb.NewOverlayDB(store)) + sink := common.NewZeroCopySink(nil) + view := &node_manager.GovernanceView{ + TxHash: common.UINT256_EMPTY, + Height: 0, + View: 0, + } + view.Serialization(sink) + db.Put(utils.ConcatKey(utils.NodeManagerContractAddress, []byte(node_manager.GOVERNANCE_VIEW)), states.GenRawStorageItem(sink.Bytes())) + + peerPoolMap := &node_manager.PeerPoolMap{ + PeerPoolMap: map[string]*node_manager.PeerPoolItem{ + vconfig.PubkeyID(acct.PublicKey): { + Address: acct.Address, + Status: node_manager.ConsensusStatus, + PeerPubkey: vconfig.PubkeyID(acct.PublicKey), + Index: 0, + }, + }, + } + sink.Reset() + peerPoolMap.Serialization(sink) + db.Put(utils.ConcatKey(utils.NodeManagerContractAddress, + []byte(node_manager.PEER_POOL), utils.GetUint32Bytes(0)), states.GenRawStorageItem(sink.Bytes())) + + blk, _ := pem.Decode([]byte(cert)) + cert, _ := sm2.ParseCertificate(blk.Bytes) + root := &chainsql2.ChainsqlRoot{ + RootCA: cert, + } + sink = common.NewZeroCopySink(nil) + root.Serialization(sink) + db.Put(utils.ConcatKey(utils.HeaderSyncContractAddress, []byte(common3.ROOT_CERT), utils.GetUint64Bytes(6)), + states.GenRawStorageItem(sink.Bytes())) + } + signAddr, _ := types.AddressFromBookkeepers([]keypair.PublicKey{acct.PublicKey}) + ns, _ := native.NewNativeService(db, &types.Transaction{SignedAddr: []common.Address{signAddr}}, uint32(time.Now().Unix()), 0, common.Uint256{0}, 0, args, false) + return ns + } + + // secp256k1 for pubkey + rootCA = `-----BEGIN CERTIFICATE----- +MIIBYDCCAQUCCQDG5aP//Iy2ITAKBggqhkjOPQQDAjA5MRwwGgYDVQQDDBN3d3cu +cGVlcnNhZmUuY25DPVVTMRkwFwYDVQQHDBBCZWlqaW5nIENIQU9ZQU5HMB4XDTIy +MDcxMjExMTUxM1oXDTIzMDcxMjExMTUxM1owOTEcMBoGA1UEAwwTd3d3LnBlZXJz +YWZlLmNuQz1VUzEZMBcGA1UEBwwQQmVpamluZyBDSEFPWUFORzBWMBAGByqGSM49 +AgEGBSuBBAAKA0IABOqcH14jODlTr/y2ji3U0Z8ENzF4I77Uc5wY8jKZ1+rgQKZ7 +0XXEoc7YUKkh6DRrsC66TSbHKlOKePISpJ3xa2MwCgYIKoZIzj0EAwIDSQAwRgIh +AOJoC9uSfOGl/x2wnwW5xUpRTJoQA+zIwBih63HvvdyBAiEAqF3IlgFHPBAShWGk +2A7kpLBW2/MnT12QyC26hvth2gM= +-----END CERTIFICATE-----` + + agencyCA = `-----BEGIN CERTIFICATE----- +MIIBYDCCAQUCCQDG5aP//Iy2ITAKBggqhkjOPQQDAjA5MRwwGgYDVQQDDBN3d3cu +cGVlcnNhZmUuY25DPVVTMRkwFwYDVQQHDBBCZWlqaW5nIENIQU9ZQU5HMB4XDTIy +MDcxMjExMTUxM1oXDTIzMDcxMjExMTUxM1owOTEcMBoGA1UEAwwTd3d3LnBlZXJz +YWZlLmNuQz1VUzEZMBcGA1UEBwwQQmVpamluZyBDSEFPWUFORzBWMBAGByqGSM49 +AgEGBSuBBAAKA0IABOqcH14jODlTr/y2ji3U0Z8ENzF4I77Uc5wY8jKZ1+rgQKZ7 +0XXEoc7YUKkh6DRrsC66TSbHKlOKePISpJ3xa2MwCgYIKoZIzj0EAwIDSQAwRgIh +AOJoC9uSfOGl/x2wnwW5xUpRTJoQA+zIwBih63HvvdyBAiEAqF3IlgFHPBAShWGk +2A7kpLBW2/MnT12QyC26hvth2gM= +-----END CERTIFICATE-----` + + nodeCA = `-----BEGIN CERTIFICATE----- +MIICOjCCAeGgAwIBAgIJAK29Ojq6GKR/MAoGCCqGSM49BAMCMDkxHDAaBgNVBAMM +E3d3dy5wZWVyc2FmZS5jbkM9VVMxGTAXBgNVBAcMEEJlaWppbmcgQ0hBT1lBTkcw +HhcNMjIwNzEzMDIxNzI0WhcNMjMwNzEzMDIxNzI0WjCBgDELMAkGA1UEBhMCVVMx +EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuc2lzY28xETAP +BgNVBAoMCE1Mb3BzSHViMRUwEwYDVQQLDAxNbG9wc0h1YiBEZXYxGjAYBgNVBAMM +EWRlbW8ubWxvcHNodWIuY29tMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEqzH+rlXB +v0H3f2WsTeU0p679KzPu+7qSRnorTrXjjJo9srNgNPiaa/9C/tX/up4TsWZvpAtz +QXoRfFUJ9eWBe6OBjDCBiTBTBgNVHSMETDBKoT2kOzA5MRwwGgYDVQQDDBN3d3cu +cGVlcnNhZmUuY25DPVVTMRkwFwYDVQQHDBBCZWlqaW5nIENIQU9ZQU5HggkAxuWj +//yMtiEwCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAwGgYDVR0RBBMwEYIPd3d3LnBl +ZXJzYWZlLmNuMAoGCCqGSM49BAMCA0cAMEQCIANla2bAh2xbtY8e3MnVLXWBhSss +OWRHBAXdwwh8oJxGAiB2VzALkw3au6buj0M6yIRzRaPuY0z4jfM2klrpG23jmA== +-----END CERTIFICATE-----` + + nodeK = `-----BEGIN PRIVATE KEY----- +MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgZ/BF7dM6KiTq6Xvf1OM7 +Are3ZZ38mMxTICL6k0hgRLShRANCAASrMf6uVcG/Qfd/ZaxN5TSnrv0rM+77upJG +eitOteOMmj2ys2A0+Jpr/0L+1f+6nhOxZm+kC3NBehF8VQn15YF7 +-----END PRIVATE KEY-----` +) + +func TestChainsqlHandler_MakeDepositProposal(t *testing.T) { + param := common2.MakeTxParam{} + param.TxHash = common.UINT256_EMPTY.ToArray() + param.Method = "test" + sink := common.NewZeroCopySink(nil) + param.Serialization(sink) + + blk, _ := pem.Decode([]byte(nodeK)) + key, err := pkcs12.ParsePKCS8PrivateKey(blk.Bytes) + if err != nil { + t.Fatal(err) + } + priv := key.(*ecdsa.PrivateKey) + + // the choise of hash according to the algo for signing + // here is SHA256 + hasher := sm2.SHA256.New() + val := sink.Bytes() + hasher.Write(val) + raw := hasher.Sum(nil) + sig, err := priv.Sign(rand.Reader, raw, nil) + if err != nil { + t.Fatal(err) + } + + caSet := &common3.CertTrustChain{ + Certs: make([]*sm2.Certificate, 2), + } + blk, _ = pem.Decode([]byte(agencyCA)) + caSet.Certs[0], err = sm2.ParseCertificate(blk.Bytes) + if err != nil { + t.Fatal(err) + } + blk, _ = pem.Decode([]byte(nodeCA)) + caSet.Certs[1], _ = sm2.ParseCertificate(blk.Bytes) + sink = common.NewZeroCopySink(nil) + caSet.Serialization(sink) + + params := new(common2.EntranceParam) + params.Proof = sig + params.Extra = val + params.SourceChainID = 6 + params.HeaderOrCrossChainMsg = sink.Bytes() + sink = common.NewZeroCopySink(nil) + params.Serialization(sink) + + ns := getNativeFunc(sink.Bytes(), nil, rootCA) + h := NewChainsqlHandler() + p, err := h.MakeDepositProposal(ns) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, p.Method, "test") +} diff --git a/native/service/cross_chain_manager/chainsql/utils.go b/native/service/cross_chain_manager/chainsql/utils.go new file mode 100644 index 00000000..a39f2566 --- /dev/null +++ b/native/service/cross_chain_manager/chainsql/utils.go @@ -0,0 +1,49 @@ +/* + * 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 . + */ +package chainsql + +import ( + "fmt" + "github.com/polynetwork/poly/core/states" + "github.com/polynetwork/poly/native" + "github.com/polynetwork/poly/native/service/header_sync/common" + "github.com/polynetwork/poly/native/service/utils" +) + +func PutChainsqlLatestHeightInProcessing(ns *native.NativeService, chainID uint64, fromContract []byte, height uint32) { + last, _ := GetChainsqlLatestHeightInProcessing(ns, chainID, fromContract) + if height <= last { + return + } + ns.GetCacheDB().Put(utils.ConcatKey(utils.CrossChainManagerContractAddress, []byte(common.LATEST_HEIGHT_IN_PROCESSING), utils.GetUint64Bytes(chainID), fromContract), + utils.GetUint32Bytes(height)) +} + +func GetChainsqlLatestHeightInProcessing(ns *native.NativeService, chainID uint64, fromContract []byte) (uint32, error) { + store, err := ns.GetCacheDB().Get(utils.ConcatKey(utils.CrossChainManagerContractAddress, []byte(common.LATEST_HEIGHT_IN_PROCESSING), utils.GetUint64Bytes(chainID), fromContract)) + if err != nil { + return 0, fmt.Errorf("GetChainsqlRoot, get root error: %v", err) + } + if store == nil { + return 0, fmt.Errorf("GetChainsqlRoot, can not find any records") + } + raw, err := states.GetValueFromRawStorageItem(store) + if err != nil { + return 0, fmt.Errorf("GetChainsqlRoot, deserialize from raw storage item err: %v", err) + } + return utils.GetBytesUint32(raw), nil +} diff --git a/native/service/cross_chain_manager/entrance.go b/native/service/cross_chain_manager/entrance.go index 85cb17a6..31366396 100644 --- a/native/service/cross_chain_manager/entrance.go +++ b/native/service/cross_chain_manager/entrance.go @@ -19,6 +19,7 @@ package cross_chain_manager import ( "encoding/hex" "fmt" + "github.com/polynetwork/poly/native/service/cross_chain_manager/chainsql" "github.com/polynetwork/poly/native/service/cross_chain_manager/fabric" "github.com/polynetwork/poly/native/service/cross_chain_manager/fisco" @@ -72,6 +73,8 @@ func GetChainHandler(router uint64) (scom.ChainHandler, error) { return fisco.NewFiscoHandler(), nil case utils.FABRIC_ROUTER: return fabric.NewFabricHandler(), nil + case utils.CHAINSQL_ROUTER: + return chainsql.NewChainsqlHandler(),nil default: return nil, fmt.Errorf("not a supported router:%d", router) } diff --git a/native/service/header_sync/chainsql/root_ca_sync.go b/native/service/header_sync/chainsql/root_ca_sync.go new file mode 100644 index 00000000..4f902eae --- /dev/null +++ b/native/service/header_sync/chainsql/root_ca_sync.go @@ -0,0 +1,89 @@ +/* + * 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 . + */ +package chainsql + +import ( + "encoding/pem" + "fmt" + "github.com/polynetwork/poly/common" + "github.com/polynetwork/poly/native" + "github.com/polynetwork/poly/native/service/governance/node_manager" + scom "github.com/polynetwork/poly/native/service/header_sync/common" + "github.com/polynetwork/poly/native/service/utils" + "github.com/tjfoc/gmsm/sm2" +) + +type ChainsqlHandler struct{} + +func NewChainsqlHandler() *ChainsqlHandler { + return &ChainsqlHandler{} +} + +func (this *ChainsqlHandler) SyncGenesisHeader(ns *native.NativeService) error { + params := new(scom.SyncGenesisHeaderParam) + if err := params.Deserialization(common.NewZeroCopySource(ns.GetInput())); err != nil { + return fmt.Errorf("ChainsqlHandler SyncGenesisHeader, contract params deserialize error: %v", err) + } + + // Get current epoch operator + operatorAddress, err := node_manager.GetCurConOperator(ns) + if err != nil { + return fmt.Errorf("ChainsqlHandler SyncGenesisHeader, get current consensus operator address error: %v", err) + } + // check witness + err = utils.ValidateOwner(ns, operatorAddress) + if err != nil { + return fmt.Errorf("ChainsqlHandler SyncGenesisHeader, checkWitness error: %v", err) + } + + blk, _ := pem.Decode(params.GenesisHeader) + if blk == nil { + return fmt.Errorf("ChainsqlHandler SyncGenesisHeader, failed to decode PEM formatted block") + } + if blk.Type != "CERTIFICATE" { + return fmt.Errorf("ChainsqlHandler SyncGenesisHeader, wrong block type: %s", blk.Type) + } + cert, err := sm2.ParseCertificate(blk.Bytes) + if err != nil { + return fmt.Errorf("ChainsqlHandler SyncGenesisHeader, failed to parse certificate: %v", err) + } + + now := ns.GetBlockTime() + if now.After(cert.NotAfter) || now.Before(cert.NotBefore) { + return fmt.Errorf("ChainsqlHandler SyncGenesisHeader, wrong time for new CA: "+ + "(start: %d, end: %d, block_time: %d)", + cert.NotBefore.Unix(), cert.NotAfter.Unix(), now.Unix()) + } + + root := &ChainsqlRoot{ + RootCA: cert, + } + + if err = PutChainsqlRoot(ns, root, params.ChainID); err != nil { + return fmt.Errorf("ChainsqlHandler SyncGenesisHeader, failed to put new Chainsql root CA into storage: %v", err) + } + + return nil +} + +func (this *ChainsqlHandler) SyncBlockHeader(ns *native.NativeService) error { + return nil +} + +func (this *ChainsqlHandler) SyncCrossChainMsg(ns *native.NativeService) error { + return nil +} diff --git a/native/service/header_sync/chainsql/root_ca_sync_test.go b/native/service/header_sync/chainsql/root_ca_sync_test.go new file mode 100644 index 00000000..3756a26c --- /dev/null +++ b/native/service/header_sync/chainsql/root_ca_sync_test.go @@ -0,0 +1,124 @@ +/* + * 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 . + */ +package chainsql + +import ( + "encoding/pem" + "github.com/ontio/ontology-crypto/keypair" + "github.com/polynetwork/poly/account" + "github.com/polynetwork/poly/common" + "github.com/polynetwork/poly/consensus/vbft/config" + "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/node_manager" + common2 "github.com/polynetwork/poly/native/service/header_sync/common" + "github.com/polynetwork/poly/native/service/utils" + "github.com/polynetwork/poly/native/storage" + "github.com/stretchr/testify/assert" + "testing" +) + +var ( + acct = account.NewAccount("") + + getNativeFunc = func(args []byte, db *storage.CacheDB) *native.NativeService { + if db == nil { + store, _ := leveldbstore.NewMemLevelDBStore() + db = storage.NewCacheDB(overlaydb.NewOverlayDB(store)) + sink := common.NewZeroCopySink(nil) + view := &node_manager.GovernanceView{ + TxHash: common.UINT256_EMPTY, + Height: 0, + View: 0, + } + view.Serialization(sink) + db.Put(utils.ConcatKey(utils.NodeManagerContractAddress, []byte(node_manager.GOVERNANCE_VIEW)), states.GenRawStorageItem(sink.Bytes())) + + peerPoolMap := &node_manager.PeerPoolMap{ + PeerPoolMap: map[string]*node_manager.PeerPoolItem{ + vconfig.PubkeyID(acct.PublicKey): { + Address: acct.Address, + Status: node_manager.ConsensusStatus, + PeerPubkey: vconfig.PubkeyID(acct.PublicKey), + Index: 0, + }, + }, + } + sink.Reset() + peerPoolMap.Serialization(sink) + db.Put(utils.ConcatKey(utils.NodeManagerContractAddress, + []byte(node_manager.PEER_POOL), utils.GetUint32Bytes(0)), states.GenRawStorageItem(sink.Bytes())) + } + signAddr, _ := types.AddressFromBookkeepers([]keypair.PublicKey{acct.PublicKey}) + ns, _ := native.NewNativeService(db, &types.Transaction{SignedAddr: []common.Address{signAddr}}, 1600945402, 0, common.Uint256{0}, 0, args, false) + return ns + } + + rootCA = `-----BEGIN CERTIFICATE----- +MIIBxDCCAWqgAwIBAgIJAL0TiHo7dsqWMAoGCCqBHM9VAYN1MDcxEDAOBgNVBAMM +B2dtY2hhaW4xEzARBgNVBAoMCmZpc2NvLWJjb3MxDjAMBgNVBAsMBWNoYWluMCAX +DTIwMDkyNDExMDMyMVoYDzIxMjAwODMxMTEwMzIxWjA3MRAwDgYDVQQDDAdnbWNo +YWluMRMwEQYDVQQKDApmaXNjby1iY29zMQ4wDAYDVQQLDAVjaGFpbjBZMBMGByqG +SM49AgEGCCqBHM9VAYItA0IABEIf/hJjT6DAGYWCyP99sBoTF2cCqpbLsrOf+NwY +KY0zdXUA9BwYCs+HyoSLRtZBlfa5hO5S6wDbU1l9472aYFijXTBbMB0GA1UdDgQW +BBQILjttksRAgGbi4KMNrLHlwPhxkTAfBgNVHSMEGDAWgBQILjttksRAgGbi4KMN +rLHlwPhxkTAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjAKBggqgRzPVQGDdQNI +ADBFAiBKFFaclfd0IKplJgLXDdAxS1Cvwhl/ZOFwPq28V2wi8gIhAPaAT8qf1hUv +9FGgtdQbPr/lerRDGOETv5Zi5GEJBOpA +-----END CERTIFICATE-----` +) + +func TestChainsqlHandler_SyncGenesisHeader(t *testing.T) { + params := new(common2.SyncGenesisHeaderParam) + params.ChainID = 6 + + params.GenesisHeader = []byte(rootCA) + sink := common.NewZeroCopySink(nil) + params.Serialization(sink) + ns := getNativeFunc(sink.Bytes(), nil) + + h := NewChainsqlHandler() + + // sync ca + if err := h.SyncGenesisHeader(ns); err != nil { + t.Fatal(err) + } + + root, err := GetChainsqlRoot(ns, 6) + if err != nil { + t.Fatal(err) + } + + blk, _ := pem.Decode([]byte(rootCA)) + if blk == nil { + t.Fatal("failed to decode pem") + } + assert.Equal(t, blk.Bytes, root.RootCA.Raw, "wrong base64-encoded bytes") + + // next successful to update + params.GenesisHeader = []byte(rootCA) + sink.Reset() + params.Serialization(sink) + ns = getNativeFunc(sink.Bytes(), ns.GetCacheDB()) + err = h.SyncGenesisHeader(ns) + if err != nil { + t.Fatal(err) + } +} diff --git a/native/service/header_sync/chainsql/states.go b/native/service/header_sync/chainsql/states.go new file mode 100644 index 00000000..1780f94a --- /dev/null +++ b/native/service/header_sync/chainsql/states.go @@ -0,0 +1,47 @@ +/* + * 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 . + */ +package chainsql + +import ( + "fmt" + pcom "github.com/polynetwork/poly/common" + "github.com/tjfoc/gmsm/sm2" +) + +type ChainsqlRoot struct { + RootCA *sm2.Certificate +} + +func (root *ChainsqlRoot) Serialization(sink *pcom.ZeroCopySink) { + sink.WriteVarBytes(root.RootCA.Raw) +} + +func (root *ChainsqlRoot) Deserialization(source *pcom.ZeroCopySource) error { + var ( + err error + ) + raw, eof := source.NextVarBytes() + if eof { + return fmt.Errorf("failed to deserialize RootCA") + } + root.RootCA, err = sm2.ParseCertificate(raw) + if err != nil { + return fmt.Errorf("failed to parse cert: %v", err) + } + + return nil +} diff --git a/native/service/header_sync/chainsql/utils.go b/native/service/header_sync/chainsql/utils.go new file mode 100644 index 00000000..71f3c42a --- /dev/null +++ b/native/service/header_sync/chainsql/utils.go @@ -0,0 +1,57 @@ +/* + * 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 . + */ +package chainsql + +import ( + "fmt" + pcom "github.com/polynetwork/poly/common" + "github.com/polynetwork/poly/core/states" + "github.com/polynetwork/poly/native" + "github.com/polynetwork/poly/native/service/header_sync/common" + "github.com/polynetwork/poly/native/service/utils" +) + +func PutChainsqlRoot(native *native.NativeService, root *ChainsqlRoot, chainID uint64) error { + contract := utils.HeaderSyncContractAddress + sink := pcom.NewZeroCopySink(nil) + root.Serialization(sink) + native.GetCacheDB().Put(utils.ConcatKey(contract, []byte(common.ROOT_CERT), utils.GetUint64Bytes(chainID)), + states.GenRawStorageItem(sink.Bytes())) + + common.NotifyPutCertificate(native, chainID, root.RootCA.Raw) + return nil +} + +func GetChainsqlRoot(native *native.NativeService, chainID uint64) (*ChainsqlRoot, error) { + store, err := native.GetCacheDB().Get(utils.ConcatKey(utils.HeaderSyncContractAddress, + []byte(common.ROOT_CERT), utils.GetUint64Bytes(chainID))) + if err != nil { + return nil, fmt.Errorf("GetChainsqlRoot, get root error: %v", err) + } + if store == nil { + return nil, fmt.Errorf("GetChainsqlRoot, can not find any records") + } + raw, err := states.GetValueFromRawStorageItem(store) + if err != nil { + return nil, fmt.Errorf("GetChainsqlRoot, deserialize from raw storage item err: %v", err) + } + root := &ChainsqlRoot{} + if err = root.Deserialization(pcom.NewZeroCopySource(raw)); err != nil { + return nil, fmt.Errorf("GetChainsqlRoot, failed to deserialize ChainsqlRoot: %v", err) + } + return root, nil +} diff --git a/native/service/header_sync/entrance.go b/native/service/header_sync/entrance.go index fae503c0..e1b27e93 100644 --- a/native/service/header_sync/entrance.go +++ b/native/service/header_sync/entrance.go @@ -19,6 +19,7 @@ package header_sync import ( "fmt" + "github.com/polynetwork/poly/native/service/header_sync/chainsql" "github.com/polynetwork/poly/native/service/header_sync/fabric" "github.com/polynetwork/poly/native/service/header_sync/fisco" @@ -67,6 +68,8 @@ func GetChainHandler(router uint64) (hscommon.HeaderSyncHandler, error) { return fisco.NewFiscoHandler(), nil case utils.FABRIC_ROUTER: return fabric.NewFabricHandler(), nil + case utils.CHAINSQL_ROUTER: + return chainsql.NewChainsqlHandler(), nil default: return nil, fmt.Errorf("not a supported router: %d", router) } diff --git a/native/service/utils/params.go b/native/service/utils/params.go index f144fd5c..8cf4e5d3 100644 --- a/native/service/utils/params.go +++ b/native/service/utils/params.go @@ -46,4 +46,5 @@ var ( FISCO_ROUTER = uint64(6) FABRIC_ROUTER = uint64(7) QUORUM_ROUTER = uint64(8) + CHAINSQL_ROUTER = uint64(9) )