forked from TrueCloudLab/neoneo-go
stateroot: only send stateroot message once per validators count
Actually fix #1922.
This commit is contained in:
parent
4a45abe3e0
commit
3d49f7d99a
5 changed files with 44 additions and 6 deletions
|
@ -224,6 +224,15 @@ func TestStateRootFull(t *testing.T) {
|
|||
require.NotNil(t, lastValidated.Load().(*payload.Extensible))
|
||||
|
||||
msg := new(stateroot.Message)
|
||||
require.NoError(t, testserdes.DecodeBinary(lastValidated.Load().(*payload.Extensible).Data, msg))
|
||||
require.NotEqual(t, stateroot.RootT, msg.Type) // not a sender for this root
|
||||
|
||||
r, err = srv.GetStateRoot(3)
|
||||
require.NoError(t, err)
|
||||
require.Error(t, srv.AddSignature(2, 0, accs[0].PrivateKey().SignHashable(uint32(netmode.UnitTestNet), r)))
|
||||
require.NoError(t, srv.AddSignature(3, 0, accs[0].PrivateKey().SignHashable(uint32(netmode.UnitTestNet), r)))
|
||||
require.NotNil(t, lastValidated.Load().(*payload.Extensible))
|
||||
|
||||
require.NoError(t, testserdes.DecodeBinary(lastValidated.Load().(*payload.Extensible).Data, msg))
|
||||
require.Equal(t, stateroot.RootT, msg.Type)
|
||||
|
||||
|
|
|
@ -24,12 +24,12 @@ func (s *service) AddSignature(height uint32, validatorIndex int32, sig []byte)
|
|||
if !s.MainCfg.Enabled {
|
||||
return nil
|
||||
}
|
||||
_, acc := s.getAccount()
|
||||
myIndex, acc := s.getAccount()
|
||||
if acc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
incRoot := s.getIncompleteRoot(height)
|
||||
incRoot := s.getIncompleteRoot(height, myIndex)
|
||||
if incRoot == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -58,20 +58,24 @@ func (s *service) GetConfig() config.StateRoot {
|
|||
return s.MainCfg
|
||||
}
|
||||
|
||||
func (s *service) getIncompleteRoot(height uint32) *incompleteRoot {
|
||||
func (s *service) getIncompleteRoot(height uint32, myIndex byte) *incompleteRoot {
|
||||
s.srMtx.Lock()
|
||||
defer s.srMtx.Unlock()
|
||||
if incRoot, ok := s.incompleteRoots[height]; ok {
|
||||
return incRoot
|
||||
}
|
||||
incRoot := &incompleteRoot{svList: s.GetStateValidators(height), sigs: make(map[string]*rootSig)}
|
||||
incRoot := &incompleteRoot{
|
||||
myIndex: int(myIndex),
|
||||
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 {
|
||||
if !ir.isSenderNow() {
|
||||
return
|
||||
}
|
||||
sr, ready := ir.finalize()
|
||||
|
|
|
@ -118,6 +118,14 @@ func (s *service) OnPayload(ep *payload.Extensible) error {
|
|||
s.log.Error("can't add SV-signed state root", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
s.srMtx.Lock()
|
||||
ir, ok := s.incompleteRoots[sr.Index]
|
||||
s.srMtx.Unlock()
|
||||
if ok {
|
||||
ir.Lock()
|
||||
ir.isSent = true
|
||||
ir.Unlock()
|
||||
}
|
||||
return err
|
||||
case VoteT:
|
||||
v := m.Payload.(*Vote)
|
||||
|
|
|
@ -24,6 +24,8 @@ type (
|
|||
root *state.MPTRoot
|
||||
// sigs contains signature from every oracle node.
|
||||
sigs map[string]*rootSig
|
||||
// myIndex is the index of validator for this root.
|
||||
myIndex int
|
||||
// myVote is an extensible message containing node's vote.
|
||||
myVote *payload.Extensible
|
||||
// retries is a counter of send attempts.
|
||||
|
@ -56,6 +58,21 @@ func (r *incompleteRoot) addSignature(pub *keys.PublicKey, sig []byte) {
|
|||
}
|
||||
}
|
||||
|
||||
func (r *incompleteRoot) isSenderNow() bool {
|
||||
if r.root == nil || r.isSent || len(r.svList) == 0 {
|
||||
return false
|
||||
}
|
||||
retries := r.retries
|
||||
if retries < 0 {
|
||||
retries = 0
|
||||
}
|
||||
ind := (int(r.root.Index) - retries) % len(r.svList)
|
||||
if ind < 0 {
|
||||
ind += len(r.svList)
|
||||
}
|
||||
return ind == r.myIndex
|
||||
}
|
||||
|
||||
// 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() (*state.MPTRoot, bool) {
|
||||
|
|
|
@ -66,7 +66,7 @@ func (s *service) signAndSend(r *state.MPTRoot) error {
|
|||
}
|
||||
|
||||
sig := acc.PrivateKey().SignHashable(uint32(s.Network), r)
|
||||
incRoot := s.getIncompleteRoot(r.Index)
|
||||
incRoot := s.getIncompleteRoot(r.Index, myIndex)
|
||||
incRoot.Lock()
|
||||
defer incRoot.Unlock()
|
||||
incRoot.root = r
|
||||
|
|
Loading…
Reference in a new issue