From d6be9d6105e611fae699a80087cd1d085518e035 Mon Sep 17 00:00:00 2001 From: Wei-Ning Huang Date: Fri, 12 Oct 2018 19:19:29 +0800 Subject: core: vm: validate if mpk, complaint, finalize is in DKG set --- core/vm/governance.go | 98 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 36 deletions(-) (limited to 'core') diff --git a/core/vm/governance.go b/core/vm/governance.go index ef7c9d6eb..f5660a92e 100644 --- a/core/vm/governance.go +++ b/core/vm/governance.go @@ -14,6 +14,7 @@ import ( coreCommon "github.com/dexon-foundation/dexon-consensus-core/common" "github.com/dexon-foundation/dexon-consensus-core/core" coreCrypto "github.com/dexon-foundation/dexon-consensus-core/core/crypto" + "github.com/dexon-foundation/dexon-consensus-core/core/crypto/ecdsa" coreTypes "github.com/dexon-foundation/dexon-consensus-core/core/types" ) @@ -573,10 +574,6 @@ func init() { } } -func nodeIDToAddress(nodeID coreTypes.NodeID) common.Address { - return common.BytesToAddress(nodeID.Bytes()[12:]) -} - // RunGovernanceContract executes governance contract. func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) ( ret []byte, err error) { @@ -717,12 +714,12 @@ func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) ( if err := method.Inputs.Unpack(&args, arguments); err != nil { return nil, errExecutionReverted } - pks := g.state.DKGMasterPublicKeys(round) - if int(index.Uint64()) >= len(pks) { + mpks := g.state.DKGMasterPublicKeys(round) + if int(index.Uint64()) >= len(mpks) { return nil, errExecutionReverted } - pk := pks[index.Uint64()] - res, err := method.Outputs.Pack(pk) + mpk := mpks[index.Uint64()] + res, err := method.Outputs.Pack(mpk) if err != nil { return nil, errExecutionReverted } @@ -1097,6 +1094,9 @@ func (s *GovernanceStateHelper) CRS(index *big.Int) common.Hash { loc := new(big.Int).Add(baseLoc, index) return s.getState(common.BigToHash(loc)) } +func (s *GovernanceStateHelper) CurrentCRS() common.Hash { + return s.CRS(new(big.Int).Sub(s.LenCRS(), big.NewInt(1))) +} func (s *GovernanceStateHelper) PushCRS(crs common.Hash) { // increase length by 1. length := s.getStateBigInt(big.NewInt(crsLoc)) @@ -1112,8 +1112,8 @@ func (s *GovernanceStateHelper) PushCRS(crs common.Hash) { func (s *GovernanceStateHelper) DKGMasterPublicKeys(round *big.Int) [][]byte { return s.read2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round) } -func (s *GovernanceStateHelper) PushDKGMasterPublicKey(round *big.Int, pk []byte) { - s.appendTo2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round, pk) +func (s *GovernanceStateHelper) PushDKGMasterPublicKey(round *big.Int, mpk []byte) { + s.appendTo2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round, mpk) } // bytes[][] public dkgComplaints; @@ -1288,7 +1288,27 @@ func (g *GovernanceContract) penalize() { g.contract.UseGas(g.contract.Gas) } +func (g *GovernanceContract) inDKGSet(nodeID coreTypes.NodeID) bool { + target := coreTypes.NewDKGSetTarget(coreCommon.Hash(g.state.CurrentCRS())) + ns := coreTypes.NewNodeSet() + + for _, x := range g.state.Nodes() { + mpk := ecdsa.NewPublicKeyFromByteSlice(x.PublicKey) + ns.Add(coreTypes.NewNodeID(mpk)) + } + + dkgSet := ns.GetSubSet(int(g.state.DKGSetSize().Uint64()), target) + _, ok := dkgSet[nodeID] + return ok +} + func (g *GovernanceContract) addDKGComplaint(round *big.Int, comp []byte) ([]byte, error) { + nextRound := g.state.LenCRS() + if round.Cmp(nextRound) != 0 { + g.penalize() + return nil, errExecutionReverted + } + caller := g.contract.Caller() // Finalized caller is not allowed to propose complaint. @@ -1312,15 +1332,15 @@ func (g *GovernanceContract) addDKGComplaint(round *big.Int, comp []byte) ([]byt g.penalize() return nil, errExecutionReverted } - verified, _ := core.VerifyDKGComplaintSignature(&dkgComplaint) - if !verified { + + // DKGComplaint must belongs to someone in DKG set. + if !g.inDKGSet(dkgComplaint.ProposerID) { g.penalize() return nil, errExecutionReverted } - // Verify that the message is sent from the caller. - signer := nodeIDToAddress(dkgComplaint.ProposerID) - if signer != caller { + verified, _ := core.VerifyDKGComplaintSignature(&dkgComplaint) + if !verified { g.penalize() return nil, errExecutionReverted } @@ -1332,7 +1352,13 @@ func (g *GovernanceContract) addDKGComplaint(round *big.Int, comp []byte) ([]byt return nil, nil } -func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, pk []byte) ([]byte, error) { +func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, mpk []byte) ([]byte, error) { + nextRound := g.state.LenCRS() + if round.Cmp(nextRound) != 0 { + g.penalize() + return nil, errExecutionReverted + } + caller := g.contract.Caller() offset := g.state.Offset(caller) @@ -1342,24 +1368,24 @@ func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, pk []byte) ([ } var dkgMasterPK coreTypes.DKGMasterPublicKey - if err := rlp.DecodeBytes(pk, &dkgMasterPK); err != nil { + if err := rlp.DecodeBytes(mpk, &dkgMasterPK); err != nil { g.penalize() return nil, errExecutionReverted } - verified, _ := core.VerifyDKGMasterPublicKeySignature(&dkgMasterPK) - if !verified { + + // DKGMasterPublicKey must belongs to someone in DKG set. + if !g.inDKGSet(dkgMasterPK.ProposerID) { g.penalize() return nil, errExecutionReverted } - // Verify that the message is sent from the caller. - signer := nodeIDToAddress(dkgMasterPK.ProposerID) - if signer != caller { + verified, _ := core.VerifyDKGMasterPublicKeySignature(&dkgMasterPK) + if !verified { g.penalize() return nil, errExecutionReverted } - g.state.PushDKGMasterPublicKey(round, pk) + g.state.PushDKGMasterPublicKey(round, mpk) // DKG operation is expensive. g.contract.UseGas(100000) @@ -1367,6 +1393,12 @@ func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, pk []byte) ([ } func (g *GovernanceContract) addDKGFinalize(round *big.Int, finalize []byte) ([]byte, error) { + nextRound := g.state.LenCRS() + if round.Cmp(nextRound) != 0 { + g.penalize() + return nil, errExecutionReverted + } + caller := g.contract.Caller() var dkgFinalize coreTypes.DKGFinalize @@ -1374,15 +1406,15 @@ func (g *GovernanceContract) addDKGFinalize(round *big.Int, finalize []byte) ([] g.penalize() return nil, errExecutionReverted } - verified, _ := core.VerifyDKGFinalizeSignature(&dkgFinalize) - if !verified { + + // DKGFInalize must belongs to someone in DKG set. + if !g.inDKGSet(dkgFinalize.ProposerID) { g.penalize() return nil, errExecutionReverted } - // Verify that the message is sent from the caller. - signer := nodeIDToAddress(dkgFinalize.ProposerID) - if signer != caller { + verified, _ := core.VerifyDKGFinalizeSignature(&dkgFinalize) + if !verified { g.penalize() return nil, errExecutionReverted } @@ -1418,12 +1450,6 @@ func (g *GovernanceContract) stake(publicKey []byte) ([]byte, error) { return nil, errExecutionReverted } - pk, err := crypto.DecompressPubkey(publicKey) - if err != nil { - g.penalize() - return nil, errExecutionReverted - } - offset = g.state.NodesLength() g.state.PushNode(&nodeInfo{ Owner: caller, @@ -1476,9 +1502,9 @@ func (g *GovernanceContract) proposeCRS(signedCRS []byte) ([]byte, error) { // Prepare DKGMasterPublicKeys. // TODO(w): make sure DKGMasterPKs are unique. var dkgMasterPKs []*coreTypes.DKGMasterPublicKey - for _, pk := range g.state.DKGMasterPublicKeys(round) { + for _, mpk := range g.state.DKGMasterPublicKeys(round) { x := new(coreTypes.DKGMasterPublicKey) - if err := rlp.DecodeBytes(pk, x); err != nil { + if err := rlp.DecodeBytes(mpk, x); err != nil { panic(err) } dkgMasterPKs = append(dkgMasterPKs, x) -- cgit v1.2.3