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
|
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)
|
incRoot := s.getIncompleteRoot(height)
|
||||||
if incRoot == nil {
|
if incRoot == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
incRoot.Lock()
|
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 {
|
if incRoot.root != nil {
|
||||||
ok := pub.VerifyHashable(sig, uint32(s.Network), incRoot.root)
|
ok := pub.VerifyHashable(sig, uint32(s.Network), incRoot.root)
|
||||||
if !ok {
|
if !ok {
|
||||||
incRoot.Unlock()
|
|
||||||
return fmt.Errorf("invalid state root signature for %d", validatorIndex)
|
return fmt.Errorf("invalid state root signature for %d", validatorIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
incRoot.addSignature(pub, sig)
|
incRoot.addSignature(pub, sig)
|
||||||
sr, ready := incRoot.finalize(pubs)
|
s.trySendRoot(incRoot, acc)
|
||||||
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)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,11 +62,27 @@ func (s *service) getIncompleteRoot(height uint32) *incompleteRoot {
|
||||||
if incRoot, ok := s.incompleteRoots[height]; ok {
|
if incRoot, ok := s.incompleteRoots[height]; ok {
|
||||||
return incRoot
|
return incRoot
|
||||||
}
|
}
|
||||||
incRoot := &incompleteRoot{sigs: make(map[string]*rootSig)}
|
incRoot := &incompleteRoot{svList: s.GetStateValidators(height), sigs: make(map[string]*rootSig)}
|
||||||
s.incompleteRoots[height] = incRoot
|
s.incompleteRoots[height] = incRoot
|
||||||
return 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) {
|
func (s *service) sendValidatedRoot(r *state.MPTRoot, acc *wallet.Account) {
|
||||||
priv := acc.PrivateKey()
|
priv := acc.PrivateKey()
|
||||||
w := io.NewBufBinWriter()
|
w := io.NewBufBinWriter()
|
||||||
|
|
|
@ -15,6 +15,8 @@ import (
|
||||||
type (
|
type (
|
||||||
incompleteRoot struct {
|
incompleteRoot struct {
|
||||||
sync.RWMutex
|
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 is true state root was already broadcasted.
|
||||||
isSent bool
|
isSent bool
|
||||||
// request is oracle request.
|
// 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
|
// 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.
|
// 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 {
|
if r.root == nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
m := smartcontract.GetDefaultHonestNodeCount(len(stateValidators))
|
m := smartcontract.GetDefaultHonestNodeCount(len(r.svList))
|
||||||
sigs := make([][]byte, 0, m)
|
sigs := make([][]byte, 0, m)
|
||||||
for _, pub := range stateValidators {
|
for _, pub := range r.svList {
|
||||||
sig, ok := r.sigs[string(pub.Bytes())]
|
sig, ok := r.sigs[string(pub.Bytes())]
|
||||||
if ok && sig.ok {
|
if ok && sig.ok {
|
||||||
sigs = append(sigs, sig.sig)
|
sigs = append(sigs, sig.sig)
|
||||||
|
@ -71,7 +73,7 @@ func (r *incompleteRoot) finalize(stateValidators keys.PublicKeys) (*state.MPTRo
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
verif, err := smartcontract.CreateDefaultMultiSigRedeemScript(stateValidators)
|
verif, err := smartcontract.CreateDefaultMultiSigRedeemScript(r.svList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ func (s *service) signAndSend(r *state.MPTRoot) error {
|
||||||
incRoot.root = r
|
incRoot.root = r
|
||||||
incRoot.addSignature(acc.PrivateKey().PublicKey(), sig)
|
incRoot.addSignature(acc.PrivateKey().PublicKey(), sig)
|
||||||
incRoot.reverify(s.Network)
|
incRoot.reverify(s.Network)
|
||||||
|
s.trySendRoot(incRoot, acc)
|
||||||
incRoot.Unlock()
|
incRoot.Unlock()
|
||||||
|
|
||||||
msg := NewMessage(VoteT, &Vote{
|
msg := NewMessage(VoteT, &Vote{
|
||||||
|
|
Loading…
Reference in a new issue