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))
|
require.NotNil(t, lastValidated.Load().(*payload.Extensible))
|
||||||
|
|
||||||
msg := new(stateroot.Message)
|
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.NoError(t, testserdes.DecodeBinary(lastValidated.Load().(*payload.Extensible).Data, msg))
|
||||||
require.Equal(t, stateroot.RootT, msg.Type)
|
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 {
|
if !s.MainCfg.Enabled {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_, acc := s.getAccount()
|
myIndex, acc := s.getAccount()
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
incRoot := s.getIncompleteRoot(height)
|
incRoot := s.getIncompleteRoot(height, myIndex)
|
||||||
if incRoot == nil {
|
if incRoot == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -58,20 +58,24 @@ func (s *service) GetConfig() config.StateRoot {
|
||||||
return s.MainCfg
|
return s.MainCfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) getIncompleteRoot(height uint32) *incompleteRoot {
|
func (s *service) getIncompleteRoot(height uint32, myIndex byte) *incompleteRoot {
|
||||||
s.srMtx.Lock()
|
s.srMtx.Lock()
|
||||||
defer s.srMtx.Unlock()
|
defer s.srMtx.Unlock()
|
||||||
if incRoot, ok := s.incompleteRoots[height]; ok {
|
if incRoot, ok := s.incompleteRoots[height]; ok {
|
||||||
return incRoot
|
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
|
s.incompleteRoots[height] = incRoot
|
||||||
return incRoot
|
return incRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
// trySendRoot attempts to finalize and send MPTRoot, it must be called with ir locked.
|
// trySendRoot attempts to finalize and send MPTRoot, it must be called with ir locked.
|
||||||
func (s *service) trySendRoot(ir *incompleteRoot, acc *wallet.Account) {
|
func (s *service) trySendRoot(ir *incompleteRoot, acc *wallet.Account) {
|
||||||
if ir.isSent {
|
if !ir.isSenderNow() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sr, ready := ir.finalize()
|
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))
|
s.log.Error("can't add SV-signed state root", zap.Error(err))
|
||||||
return nil
|
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
|
return err
|
||||||
case VoteT:
|
case VoteT:
|
||||||
v := m.Payload.(*Vote)
|
v := m.Payload.(*Vote)
|
||||||
|
|
|
@ -24,6 +24,8 @@ type (
|
||||||
root *state.MPTRoot
|
root *state.MPTRoot
|
||||||
// sigs contains signature from every oracle node.
|
// sigs contains signature from every oracle node.
|
||||||
sigs map[string]*rootSig
|
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 is an extensible message containing node's vote.
|
||||||
myVote *payload.Extensible
|
myVote *payload.Extensible
|
||||||
// retries is a counter of send attempts.
|
// 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
|
// 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() (*state.MPTRoot, bool) {
|
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)
|
sig := acc.PrivateKey().SignHashable(uint32(s.Network), r)
|
||||||
incRoot := s.getIncompleteRoot(r.Index)
|
incRoot := s.getIncompleteRoot(r.Index, myIndex)
|
||||||
incRoot.Lock()
|
incRoot.Lock()
|
||||||
defer incRoot.Unlock()
|
defer incRoot.Unlock()
|
||||||
incRoot.root = r
|
incRoot.root = r
|
||||||
|
|
Loading…
Reference in a new issue