2021-04-30 19:55:12 +00:00
|
|
|
package consensus
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/Secured-Finance/dione/cache"
|
|
|
|
types2 "github.com/Secured-Finance/dione/consensus/types"
|
|
|
|
"github.com/Secured-Finance/dione/consensus/validation"
|
2021-05-13 11:49:38 +00:00
|
|
|
"github.com/Secured-Finance/dione/contracts/dioneOracle"
|
2021-04-30 19:55:12 +00:00
|
|
|
"github.com/Secured-Finance/dione/types"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/filecoin-project/go-state-types/crypto"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
type ConsensusValidator struct {
|
|
|
|
validationFuncMap map[types2.MessageType]func(msg types2.Message) bool
|
2021-05-13 11:49:38 +00:00
|
|
|
cache cache.Cache
|
2021-04-30 19:55:12 +00:00
|
|
|
miner *Miner
|
|
|
|
}
|
|
|
|
|
2021-05-13 11:49:38 +00:00
|
|
|
func NewConsensusValidator(ec cache.Cache, miner *Miner) *ConsensusValidator {
|
2021-04-30 19:55:12 +00:00
|
|
|
cv := &ConsensusValidator{
|
2021-05-13 11:49:38 +00:00
|
|
|
cache: ec,
|
|
|
|
miner: miner,
|
2021-04-30 19:55:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cv.validationFuncMap = map[types2.MessageType]func(msg types2.Message) bool{
|
|
|
|
types2.MessageTypePrePrepare: func(msg types2.Message) bool {
|
|
|
|
// TODO here we need to do validation of tx itself
|
|
|
|
consensusMsg := msg.Payload
|
|
|
|
|
|
|
|
// === verify task signature ===
|
|
|
|
err := VerifyTaskSignature(consensusMsg.Task)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("unable to verify signature: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
/////////////////////////////////
|
|
|
|
|
2021-05-13 11:49:38 +00:00
|
|
|
// === verify if request exists in cache ===
|
|
|
|
var requestEvent *dioneOracle.DioneOracleNewOracleRequest
|
|
|
|
err = cv.cache.Get("request_"+consensusMsg.Task.RequestID, &requestEvent)
|
2021-04-30 19:55:12 +00:00
|
|
|
if err != nil {
|
2021-05-13 11:49:38 +00:00
|
|
|
logrus.Errorf("the request doesn't exist in the cache or has been failed to decode: %v", err)
|
2021-04-30 19:55:12 +00:00
|
|
|
return false
|
|
|
|
}
|
2021-05-13 11:49:38 +00:00
|
|
|
|
2021-04-30 19:55:12 +00:00
|
|
|
if requestEvent.OriginChain != consensusMsg.Task.OriginChain ||
|
|
|
|
requestEvent.RequestType != consensusMsg.Task.RequestType ||
|
|
|
|
requestEvent.RequestParams != consensusMsg.Task.RequestParams {
|
|
|
|
|
2021-05-13 11:49:38 +00:00
|
|
|
logrus.Errorf("the incoming task and cached request requestEvent don't match!")
|
2021-04-30 19:55:12 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
/////////////////////////////////
|
|
|
|
|
|
|
|
// === verify election proof wincount preliminarily ===
|
|
|
|
if consensusMsg.Task.ElectionProof.WinCount < 1 {
|
|
|
|
logrus.Error("miner isn't a winner!")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
/////////////////////////////////
|
|
|
|
|
|
|
|
// === verify miner's eligibility to propose this task ===
|
|
|
|
err = cv.miner.IsMinerEligibleToProposeTask(common.HexToAddress(consensusMsg.Task.MinerEth))
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("miner is not eligible to propose task: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
/////////////////////////////////
|
|
|
|
|
|
|
|
// === verify election proof vrf ===
|
|
|
|
minerAddressMarshalled, err := consensusMsg.Task.Miner.MarshalBinary()
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("failed to marshal miner address: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
electionProofRandomness, err := DrawRandomness(
|
|
|
|
consensusMsg.Task.BeaconEntries[1].Data,
|
|
|
|
crypto.DomainSeparationTag_ElectionProofProduction,
|
|
|
|
consensusMsg.Task.DrandRound,
|
|
|
|
minerAddressMarshalled,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("failed to draw electionProofRandomness: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
err = VerifyVRF(consensusMsg.Task.Miner, electionProofRandomness, consensusMsg.Task.ElectionProof.VRFProof)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("failed to verify election proof vrf: %v", err)
|
|
|
|
}
|
|
|
|
//////////////////////////////////////
|
|
|
|
|
|
|
|
// === verify ticket vrf ===
|
|
|
|
ticketRandomness, err := DrawRandomness(
|
|
|
|
consensusMsg.Task.BeaconEntries[1].Data,
|
|
|
|
crypto.DomainSeparationTag_TicketProduction,
|
|
|
|
consensusMsg.Task.DrandRound-types.TicketRandomnessLookback,
|
|
|
|
minerAddressMarshalled,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("failed to draw ticket electionProofRandomness: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
err = VerifyVRF(consensusMsg.Task.Miner, ticketRandomness, consensusMsg.Task.Ticket.VRFProof)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("failed to verify ticket vrf: %v", err)
|
|
|
|
}
|
|
|
|
//////////////////////////////////////
|
|
|
|
|
|
|
|
// === compute wincount locally and verify values ===
|
|
|
|
mStake, nStake, err := cv.miner.GetStakeInfo(common.HexToAddress(consensusMsg.Task.MinerEth))
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("failed to get miner stake: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
actualWinCount := consensusMsg.Task.ElectionProof.ComputeWinCount(*mStake, *nStake)
|
|
|
|
if consensusMsg.Task.ElectionProof.WinCount != actualWinCount {
|
|
|
|
logrus.Errorf("locally computed wincount isn't matching received value!", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
//////////////////////////////////////
|
|
|
|
|
|
|
|
// === validate payload by specific-chain checks ===
|
|
|
|
if validationFunc := validation.GetValidationMethod(consensusMsg.Task.OriginChain, consensusMsg.Task.RequestType); validationFunc != nil {
|
|
|
|
err := validationFunc(consensusMsg.Task.Payload)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("payload validation has failed: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
logrus.Debugf("Origin chain [%v]/request type[%v] doesn't have any payload validation!", consensusMsg.Task.OriginChain, consensusMsg.Task.RequestType)
|
|
|
|
}
|
|
|
|
/////////////////////////////////
|
|
|
|
|
|
|
|
return true
|
|
|
|
},
|
|
|
|
types2.MessageTypePrepare: func(msg types2.Message) bool {
|
|
|
|
err := VerifyTaskSignature(msg.Payload.Task)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
},
|
|
|
|
types2.MessageTypeCommit: func(msg types2.Message) bool {
|
|
|
|
err := VerifyTaskSignature(msg.Payload.Task)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
return cv
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cv *ConsensusValidator) Valid(msg types2.Message) bool {
|
|
|
|
return cv.validationFuncMap[msg.Type](msg)
|
|
|
|
}
|