aboutsummaryrefslogblamecommitdiffstats
path: root/consensus/dexcon/fake_dexcon.go
blob: 2619c9bf477dfe9d425e750d06ec16df5850755f (plain) (tree)
1
2
3
4
5
6




                      
 







                                                                                      
 





                                                              

































                                                                                       
                                                                              
                                         



























































































































































































                                                                                       





                                                                














































                                                                                
package dexcon

import (
    "crypto/ecdsa"
    "math/big"

    coreCommon "github.com/tangerine-network/tangerine-consensus/common"
    dexCore "github.com/tangerine-network/tangerine-consensus/core"
    coreCrypto "github.com/tangerine-network/tangerine-consensus/core/crypto"
    coreDKG "github.com/tangerine-network/tangerine-consensus/core/crypto/dkg"
    coreEcdsa "github.com/tangerine-network/tangerine-consensus/core/crypto/ecdsa"
    coreTypes "github.com/tangerine-network/tangerine-consensus/core/types"
    coreTypesDKG "github.com/tangerine-network/tangerine-consensus/core/types/dkg"
    coreUtils "github.com/tangerine-network/tangerine-consensus/core/utils"

    "github.com/tangerine-network/go-tangerine/common"
    "github.com/tangerine-network/go-tangerine/consensus"
    "github.com/tangerine-network/go-tangerine/core/types"
    "github.com/tangerine-network/go-tangerine/core/vm"
    "github.com/tangerine-network/go-tangerine/crypto"
    "github.com/tangerine-network/go-tangerine/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
        }
    }

    randomness := f.nodes.Randomness(header.Round, common.Hash(blockHash))
    coreBlock.Randomness = randomness

    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) {
    var signedCRS []byte
    if round < dexCore.DKGDelayRound {
        signedCRS = crypto.Keccak256(n.signedCRS[round])
    } else {
        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
}