mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 04:36:42 +00:00
consensus: use signer pubkey to check for unique signatures, close XFN-03 (#1643)
* use signer pubkey to check for unique signatures * add error handling * add go routines to process Ecrecover concurrently add input validation and early return * optimize
This commit is contained in:
parent
da92ad7ccf
commit
366c99ece3
3 changed files with 74 additions and 22 deletions
|
|
@ -812,7 +812,17 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
|
||||||
return errors.New("fail to verify QC due to failure in getting epoch switch info")
|
return errors.New("fail to verify QC due to failure in getting epoch switch info")
|
||||||
}
|
}
|
||||||
|
|
||||||
signatures, duplicates := UniqueSignatures(quorumCert.Signatures)
|
signedVoteObj := types.VoteSigHash(&types.VoteForSign{
|
||||||
|
ProposedBlockInfo: quorumCert.ProposedBlockInfo,
|
||||||
|
GapNumber: quorumCert.GapNumber,
|
||||||
|
})
|
||||||
|
|
||||||
|
signatures, duplicates, err := RecoverUniqueSigners(signedVoteObj, quorumCert.Signatures)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[verifyQC] Error while getting unique signatures from QC", "qcBlockNum", quorumCert.ProposedBlockInfo.Number, "qcRound", quorumCert.ProposedBlockInfo.Round, "qcBlockHash", quorumCert.ProposedBlockInfo.Hash, "qcSignLen", len(quorumCert.Signatures), "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if len(duplicates) != 0 {
|
if len(duplicates) != 0 {
|
||||||
for _, d := range duplicates {
|
for _, d := range duplicates {
|
||||||
log.Warn("[verifyQC] duplicated signature in QC", "duplicate", common.Bytes2Hex(d))
|
log.Warn("[verifyQC] duplicated signature in QC", "duplicate", common.Bytes2Hex(d))
|
||||||
|
|
@ -835,10 +845,7 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
|
||||||
for _, signature := range signatures {
|
for _, signature := range signatures {
|
||||||
go func(sig types.Signature) {
|
go func(sig types.Signature) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
verified, _, err := x.verifyMsgSignature(types.VoteSigHash(&types.VoteForSign{
|
verified, _, err := x.verifyMsgSignature(signedVoteObj, sig, epochInfo.Masternodes)
|
||||||
ProposedBlockInfo: quorumCert.ProposedBlockInfo,
|
|
||||||
GapNumber: quorumCert.GapNumber,
|
|
||||||
}), sig, epochInfo.Masternodes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[verifyQC] Error while verfying QC message signatures", "Error", err)
|
log.Error("[verifyQC] Error while verfying QC message signatures", "Error", err)
|
||||||
haveError = errors.New("error while verfying QC message signatures")
|
haveError = errors.New("error while verfying QC message signatures")
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,16 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
|
||||||
return errors.New("empty master node lists from snapshot")
|
return errors.New("empty master node lists from snapshot")
|
||||||
}
|
}
|
||||||
|
|
||||||
signatures, duplicates := UniqueSignatures(timeoutCert.Signatures)
|
signedTimeoutObj := types.TimeoutSigHash(&types.TimeoutForSign{
|
||||||
|
Round: timeoutCert.Round,
|
||||||
|
GapNumber: timeoutCert.GapNumber,
|
||||||
|
})
|
||||||
|
signatures, duplicates, err := RecoverUniqueSigners(signedTimeoutObj, timeoutCert.Signatures)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[verifyTC] Error while getting unique signatures", "tcRound", timeoutCert.Round, "tcGapNumber", timeoutCert.GapNumber, "tcSignLen", len(timeoutCert.Signatures), "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if len(duplicates) != 0 {
|
if len(duplicates) != 0 {
|
||||||
for _, d := range duplicates {
|
for _, d := range duplicates {
|
||||||
log.Warn("[verifyQC] duplicated signature in QC", "duplicate", common.Bytes2Hex(d))
|
log.Warn("[verifyQC] duplicated signature in QC", "duplicate", common.Bytes2Hex(d))
|
||||||
|
|
@ -164,11 +173,6 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
|
||||||
var mutex sync.Mutex
|
var mutex sync.Mutex
|
||||||
var haveError error
|
var haveError error
|
||||||
|
|
||||||
signedTimeoutObj := types.TimeoutSigHash(&types.TimeoutForSign{
|
|
||||||
Round: timeoutCert.Round,
|
|
||||||
GapNumber: timeoutCert.GapNumber,
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, signature := range signatures {
|
for _, signature := range signatures {
|
||||||
go func(sig types.Signature) {
|
go func(sig types.Signature) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/accounts"
|
"github.com/XinFinOrg/XDPoSChain/accounts"
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
|
@ -75,20 +76,60 @@ func decodeMasternodesFromHeaderExtra(checkpointHeader *types.Header) []common.A
|
||||||
return masternodes
|
return masternodes
|
||||||
}
|
}
|
||||||
|
|
||||||
func UniqueSignatures(signatureSlice []types.Signature) ([]types.Signature, []types.Signature) {
|
func RecoverUniqueSigners(signedHash common.Hash, signatureList []types.Signature) ([]types.Signature, []types.Signature, error) {
|
||||||
keys := make(map[string]bool)
|
if (signedHash == common.Hash{}) {
|
||||||
list := []types.Signature{}
|
return nil, nil, errors.New("signedHash cannot be empty")
|
||||||
duplicates := []types.Signature{}
|
}
|
||||||
for _, signature := range signatureSlice {
|
if len(signatureList) == 0 {
|
||||||
hexOfSig := common.Bytes2Hex(signature)
|
return []types.Signature{}, []types.Signature{}, nil
|
||||||
if _, value := keys[hexOfSig]; !value {
|
}
|
||||||
keys[hexOfSig] = true
|
|
||||||
list = append(list, signature)
|
type Message struct {
|
||||||
|
pubkey common.Address
|
||||||
|
sig types.Signature
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make(chan Message, len(signatureList))
|
||||||
|
errCh := make(chan error, len(signatureList))
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(len(signatureList))
|
||||||
|
for _, signature := range signatureList {
|
||||||
|
go func(sig types.Signature) {
|
||||||
|
defer wg.Done()
|
||||||
|
pubkey, err := crypto.Ecrecover(signedHash.Bytes(), signature)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[UniqueSignatures] error while recovering public key", "error", err, "signature", common.Bytes2Hex(signature), "signedHash", signedHash.Hex())
|
||||||
|
errCh <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var signerAddress common.Address
|
||||||
|
copy(signerAddress[:], crypto.Keccak256(pubkey[1:])[12:])
|
||||||
|
result <- Message{pubkey: signerAddress, sig: sig}
|
||||||
|
}(signature)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
close(result)
|
||||||
|
close(errCh)
|
||||||
|
|
||||||
|
if len(errCh) > 0 {
|
||||||
|
return nil, nil, <-errCh
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := make(map[string]struct{})
|
||||||
|
uniqueSigners := make([]types.Signature, 0, len(result))
|
||||||
|
duplicates := make([]types.Signature, 0, len(result))
|
||||||
|
for r := range result {
|
||||||
|
pubkeyHex := r.pubkey.Hex()
|
||||||
|
if _, ok := keys[pubkeyHex]; !ok {
|
||||||
|
keys[pubkeyHex] = struct{}{}
|
||||||
|
uniqueSigners = append(uniqueSigners, r.sig)
|
||||||
} else {
|
} else {
|
||||||
duplicates = append(duplicates, signature)
|
log.Warn("[UniqueSignatures] duplicate signing found", "pubkey", pubkeyHex, "signedMessage", signedHash.Hex(), "signature", r.sig)
|
||||||
|
duplicates = append(duplicates, r.sig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list, duplicates
|
|
||||||
|
return uniqueSigners, duplicates, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *XDPoS_v2) signSignature(signingHash common.Hash) (types.Signature, error) {
|
func (x *XDPoS_v2) signSignature(signingHash common.Hash) (types.Signature, error) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue