stateroot: try finalizing stateroot when adding our signature
And don't add/resend it multiple times. 1. We can be in a setup with one SV only and no AddSignature() called at all. 2. AddSignature() might add M-1 signatures and our signature should be the last one to complete MPTRoot, but we'll never do that.
This commit is contained in:
parent
847927af74
commit
d5c7a40db9
3 changed files with 32 additions and 22 deletions
|
@ -27,36 +27,27 @@ func (s *service) AddSignature(height uint32, validatorIndex int32, sig []byte)
|
|||
return nil
|
||||
}
|
||||
|
||||
pubs := s.GetStateValidators(height)
|
||||
if validatorIndex < 0 || int(validatorIndex) >= len(pubs) {
|
||||
return errors.New("invalid validator index")
|
||||
}
|
||||
pub := pubs[validatorIndex]
|
||||
|
||||
incRoot := s.getIncompleteRoot(height)
|
||||
if incRoot == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
incRoot.Lock()
|
||||
defer incRoot.Unlock()
|
||||
|
||||
if validatorIndex < 0 || int(validatorIndex) >= len(incRoot.svList) {
|
||||
return errors.New("invalid validator index")
|
||||
}
|
||||
|
||||
pub := incRoot.svList[validatorIndex]
|
||||
if incRoot.root != nil {
|
||||
ok := pub.VerifyHashable(sig, uint32(s.Network), incRoot.root)
|
||||
if !ok {
|
||||
incRoot.Unlock()
|
||||
return fmt.Errorf("invalid state root signature for %d", validatorIndex)
|
||||
}
|
||||
}
|
||||
incRoot.addSignature(pub, sig)
|
||||
sr, ready := incRoot.finalize(pubs)
|
||||
incRoot.Unlock()
|
||||
|
||||
if ready {
|
||||
err := s.AddStateRoot(sr)
|
||||
if err != nil {
|
||||
s.log.Error("can't add validated state root", zap.Error(err))
|
||||
}
|
||||
s.sendValidatedRoot(sr, acc)
|
||||
}
|
||||
s.trySendRoot(incRoot, acc)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -71,11 +62,27 @@ func (s *service) getIncompleteRoot(height uint32) *incompleteRoot {
|
|||
if incRoot, ok := s.incompleteRoots[height]; ok {
|
||||
return incRoot
|
||||
}
|
||||
incRoot := &incompleteRoot{sigs: make(map[string]*rootSig)}
|
||||
incRoot := &incompleteRoot{svList: s.GetStateValidators(height), sigs: make(map[string]*rootSig)}
|
||||
s.incompleteRoots[height] = incRoot
|
||||
return incRoot
|
||||
}
|
||||
|
||||
// trySendRoot attempts to finalize and send MPTRoot, it must be called with ir locked.
|
||||
func (s *service) trySendRoot(ir *incompleteRoot, acc *wallet.Account) {
|
||||
if ir.isSent {
|
||||
return
|
||||
}
|
||||
sr, ready := ir.finalize()
|
||||
if ready {
|
||||
err := s.AddStateRoot(sr)
|
||||
if err != nil {
|
||||
s.log.Error("can't add validated state root", zap.Error(err))
|
||||
}
|
||||
s.sendValidatedRoot(sr, acc)
|
||||
ir.isSent = true
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) sendValidatedRoot(r *state.MPTRoot, acc *wallet.Account) {
|
||||
priv := acc.PrivateKey()
|
||||
w := io.NewBufBinWriter()
|
||||
|
|
|
@ -15,6 +15,8 @@ import (
|
|||
type (
|
||||
incompleteRoot struct {
|
||||
sync.RWMutex
|
||||
// svList is a list of state validator keys for this stateroot.
|
||||
svList keys.PublicKeys
|
||||
// isSent is true state root was already broadcasted.
|
||||
isSent bool
|
||||
// request is oracle request.
|
||||
|
@ -51,14 +53,14 @@ func (r *incompleteRoot) addSignature(pub *keys.PublicKey, sig []byte) {
|
|||
|
||||
// finalize checks is either main or backup tx has sufficient number of signatures and returns
|
||||
// tx and bool value indicating if it is ready to be broadcasted.
|
||||
func (r *incompleteRoot) finalize(stateValidators keys.PublicKeys) (*state.MPTRoot, bool) {
|
||||
func (r *incompleteRoot) finalize() (*state.MPTRoot, bool) {
|
||||
if r.root == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
m := smartcontract.GetDefaultHonestNodeCount(len(stateValidators))
|
||||
m := smartcontract.GetDefaultHonestNodeCount(len(r.svList))
|
||||
sigs := make([][]byte, 0, m)
|
||||
for _, pub := range stateValidators {
|
||||
for _, pub := range r.svList {
|
||||
sig, ok := r.sigs[string(pub.Bytes())]
|
||||
if ok && sig.ok {
|
||||
sigs = append(sigs, sig.sig)
|
||||
|
@ -71,7 +73,7 @@ func (r *incompleteRoot) finalize(stateValidators keys.PublicKeys) (*state.MPTRo
|
|||
return nil, false
|
||||
}
|
||||
|
||||
verif, err := smartcontract.CreateDefaultMultiSigRedeemScript(stateValidators)
|
||||
verif, err := smartcontract.CreateDefaultMultiSigRedeemScript(r.svList)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ func (s *service) signAndSend(r *state.MPTRoot) error {
|
|||
incRoot.root = r
|
||||
incRoot.addSignature(acc.PrivateKey().PublicKey(), sig)
|
||||
incRoot.reverify(s.Network)
|
||||
s.trySendRoot(incRoot, acc)
|
||||
incRoot.Unlock()
|
||||
|
||||
msg := NewMessage(VoteT, &Vote{
|
||||
|
|
Loading…
Reference in a new issue