diff options
author | Sonic <sonic@dexon.org> | 2019-01-24 10:38:28 +0800 |
---|---|---|
committer | Wei-Ning Huang <w@dexon.org> | 2019-01-24 10:38:28 +0800 |
commit | 9f7322e463cb85ece928b214bd05c4596880d395 (patch) | |
tree | 36c0453d15ca6f36b002dd3622bc3f65a6d36c14 /consensus | |
parent | 942086cc71a13ee010182299de3b5011e3618d57 (diff) | |
download | dexon-9f7322e463cb85ece928b214bd05c4596880d395.tar dexon-9f7322e463cb85ece928b214bd05c4596880d395.tar.gz dexon-9f7322e463cb85ece928b214bd05c4596880d395.tar.bz2 dexon-9f7322e463cb85ece928b214bd05c4596880d395.tar.lz dexon-9f7322e463cb85ece928b214bd05c4596880d395.tar.xz dexon-9f7322e463cb85ece928b214bd05c4596880d395.tar.zst dexon-9f7322e463cb85ece928b214bd05c4596880d395.zip |
core, dex/downloader: polish headers verification and blocks insertion logic (#168)
Refactor GenerateDexonChain function, move governance tx logic to
the user of GenerateDexonChain (testchain_test.go) and move fake node set
code to FakeDexcon.
Diffstat (limited to 'consensus')
-rw-r--r-- | consensus/dexcon/fake_dexcon.go | 300 | ||||
-rw-r--r-- | consensus/errors.go | 2 |
2 files changed, 302 insertions, 0 deletions
diff --git a/consensus/dexcon/fake_dexcon.go b/consensus/dexcon/fake_dexcon.go new file mode 100644 index 000000000..ca48b5275 --- /dev/null +++ b/consensus/dexcon/fake_dexcon.go @@ -0,0 +1,300 @@ +package dexcon + +import ( + "crypto/ecdsa" + "math/big" + "time" + + coreCommon "github.com/dexon-foundation/dexon-consensus/common" + coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" + coreDKG "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg" + coreEcdsa "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" + coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" + coreTypesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg" + coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" + + "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/consensus" + "github.com/dexon-foundation/dexon/core/types" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/crypto" + "github.com/dexon-foundation/dexon/rlp" +) + +type FakeDexcon struct { + *Dexcon + nodes *NodeSet +} + +func NewFaker(nodes *NodeSet) *FakeDexcon { + return &FakeDexcon{ + Dexcon: New(), + nodes: nodes, + } +} + +func (f *FakeDexcon) Prepare(chain consensus.ChainReader, header *types.Header) error { + var coreBlock coreTypes.Block + if err := rlp.DecodeBytes(header.DexconMeta, &coreBlock); err != nil { + return err + } + + blockHash, err := coreUtils.HashBlock(&coreBlock) + if err != nil { + return err + } + + parentHeader := chain.GetHeaderByNumber(header.Number.Uint64() - 1) + var parentCoreBlock coreTypes.Block + if parentHeader.Number.Uint64() != 0 { + if err := rlp.DecodeBytes( + parentHeader.DexconMeta, &parentCoreBlock); err != nil { + return err + } + } + + parentCoreBlockHash, err := coreUtils.HashBlock(&parentCoreBlock) + if err != nil { + return err + } + randomness := f.nodes.Randomness(header.Round, common.Hash(blockHash)) + coreBlock.Finalization.ParentHash = parentCoreBlockHash + coreBlock.Finalization.Randomness = randomness + coreBlock.Finalization.Timestamp = time.Now().UTC() + coreBlock.Finalization.Height = parentHeader.Number.Uint64() + + dexconMeta, err := rlp.EncodeToBytes(&coreBlock) + if err != nil { + return err + } + header.DexconMeta = dexconMeta + return nil +} + +type Node struct { + cryptoKey coreCrypto.PrivateKey + ecdsaKey *ecdsa.PrivateKey + + id coreTypes.NodeID + dkgid coreDKG.ID + address common.Address + prvShares *coreDKG.PrivateKeyShares + pubShares *coreDKG.PublicKeyShares + receivedPrvShares *coreDKG.PrivateKeyShares + recoveredPrivateKey *coreDKG.PrivateKey + signer *coreUtils.Signer + txSigner types.Signer + + mpk *coreTypesDKG.MasterPublicKey +} + +func newNode(privkey *ecdsa.PrivateKey, txSigner types.Signer) *Node { + k := coreEcdsa.NewPrivateKeyFromECDSA(privkey) + id := coreTypes.NewNodeID(k.PublicKey()) + return &Node{ + cryptoKey: k, + ecdsaKey: privkey, + id: id, + dkgid: coreDKG.NewID(id.Bytes()), + address: crypto.PubkeyToAddress(privkey.PublicKey), + signer: coreUtils.NewSigner(k), + txSigner: txSigner, + } +} + +func (n *Node) ID() coreTypes.NodeID { return n.id } +func (n *Node) DKGID() coreDKG.ID { return n.dkgid } +func (n *Node) Address() common.Address { return n.address } + +func (n *Node) MasterPublicKey(round uint64) *coreTypesDKG.MasterPublicKey { + mpk := &coreTypesDKG.MasterPublicKey{ + ProposerID: n.ID(), + Round: round, + DKGID: n.DKGID(), + PublicKeyShares: *n.pubShares, + } + + if err := n.signer.SignDKGMasterPublicKey(mpk); err != nil { + panic(err) + } + return mpk +} + +func (n *Node) DKGMPKReady(round uint64) *coreTypesDKG.MPKReady { + ready := &coreTypesDKG.MPKReady{ + ProposerID: n.ID(), + Round: round, + } + + if err := n.signer.SignDKGMPKReady(ready); err != nil { + panic(err) + } + return ready +} + +func (n *Node) DKGFinalize(round uint64) *coreTypesDKG.Finalize { + final := &coreTypesDKG.Finalize{ + ProposerID: n.ID(), + Round: round, + } + + if err := n.signer.SignDKGFinalize(final); err != nil { + panic(err) + } + return final +} + +func (n *Node) CreateGovTx(nonce uint64, data []byte) *types.Transaction { + tx, err := types.SignTx(types.NewTransaction( + nonce, + vm.GovernanceContractAddress, + big.NewInt(0), + uint64(2000000), + big.NewInt(1e10), + data), n.txSigner, n.ecdsaKey) + if err != nil { + panic(err) + } + return tx +} + +type NodeSet struct { + signer types.Signer + privkeys []*ecdsa.PrivateKey + nodes map[uint64][]*Node + crs map[uint64]common.Hash + signedCRS map[uint64][]byte +} + +func NewNodeSet(round uint64, signedCRS []byte, signer types.Signer, + privkeys []*ecdsa.PrivateKey) *NodeSet { + n := &NodeSet{ + signer: signer, + privkeys: privkeys, + nodes: make(map[uint64][]*Node), + crs: make(map[uint64]common.Hash), + signedCRS: make(map[uint64][]byte), + } + n.signedCRS[round] = signedCRS + n.crs[round] = crypto.Keccak256Hash(signedCRS) + return n +} + +func (n *NodeSet) Nodes(round uint64) []*Node { + if nodes, ok := n.nodes[round]; ok { + return nodes + } + panic("dkg not ready") +} + +func (n *NodeSet) CRS(round uint64) common.Hash { + if c, ok := n.crs[round]; ok { + return c + } + panic("crs not exist") +} + +func (n *NodeSet) SignedCRS(round uint64) []byte { + if c, ok := n.signedCRS[round]; ok { + return c + } + panic("signedCRS not exist") +} + +// Assume All nodes in NodeSet are in DKG Set too. +func (n *NodeSet) RunDKG(round uint64, threshold int) { + var ids coreDKG.IDs + var nodes []*Node + for _, key := range n.privkeys { + node := newNode(key, n.signer) + nodes = append(nodes, node) + ids = append(ids, node.DKGID()) + } + + for _, node := range nodes { + node.prvShares, node.pubShares = coreDKG.NewPrivateKeyShares(threshold) + node.prvShares.SetParticipants(ids) + node.receivedPrvShares = coreDKG.NewEmptyPrivateKeyShares() + } + + // exchange keys + for _, sender := range nodes { + for _, receiver := range nodes { + // no need to verify + prvShare, ok := sender.prvShares.Share(receiver.DKGID()) + if !ok { + panic("not ok") + } + receiver.receivedPrvShares.AddShare(sender.DKGID(), prvShare) + } + } + + // recover private key + for _, node := range nodes { + privKey, err := node.receivedPrvShares.RecoverPrivateKey(ids) + if err != nil { + panic(err) + } + node.recoveredPrivateKey = privKey + } + + // store these nodes + n.nodes[round] = nodes +} + +func (n *NodeSet) Randomness(round uint64, hash common.Hash) []byte { + if round == 0 { + return []byte{} + } + return n.TSig(round, hash) +} + +func (n *NodeSet) SignCRS(round uint64) { + signedCRS := n.TSig(round, n.crs[round]) + n.signedCRS[round+1] = signedCRS + n.crs[round+1] = crypto.Keccak256Hash(signedCRS) +} + +func (n *NodeSet) TSig(round uint64, hash common.Hash) []byte { + var ids coreDKG.IDs + var psigs []coreDKG.PartialSignature + for _, node := range n.nodes[round] { + ids = append(ids, node.DKGID()) + } + for _, node := range n.nodes[round] { + sig, err := node.recoveredPrivateKey.Sign(coreCommon.Hash(hash)) + if err != nil { + panic(err) + } + psigs = append(psigs, coreDKG.PartialSignature(sig)) + // ids = append(ids, node.DKGID()) + + // FIXME: Debug verify signature + pk := coreDKG.NewEmptyPublicKeyShares() + for _, nnode := range n.nodes[round] { + p, err := nnode.pubShares.Share(node.DKGID()) + if err != nil { + panic(err) + } + err = pk.AddShare(nnode.DKGID(), p) + if err != nil { + panic(err) + } + } + + recovered, err := pk.RecoverPublicKey(ids) + if err != nil { + panic(err) + } + + if !recovered.VerifySignature(coreCommon.Hash(hash), sig) { + panic("##########can not verify signature") + } + } + + sig, err := coreDKG.RecoverSignature(psigs, ids) + if err != nil { + panic(err) + } + return sig.Signature +} diff --git a/consensus/errors.go b/consensus/errors.go index a005c5f63..204f09f21 100644 --- a/consensus/errors.go +++ b/consensus/errors.go @@ -34,4 +34,6 @@ var ( // ErrInvalidNumber is returned if a block's number doesn't equal it's parent's // plus one. ErrInvalidNumber = errors.New("invalid block number") + + ErrWitnessMismatch = errors.New("witness mismatch") ) |