github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/services/stateroot/network.go (about)

     1  package stateroot
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/nspcc-dev/neo-go/pkg/config"
     8  	"github.com/nspcc-dev/neo-go/pkg/core/state"
     9  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    10  	"github.com/nspcc-dev/neo-go/pkg/io"
    11  	"github.com/nspcc-dev/neo-go/pkg/network/payload"
    12  	"github.com/nspcc-dev/neo-go/pkg/vm/emit"
    13  	"github.com/nspcc-dev/neo-go/pkg/wallet"
    14  	"go.uber.org/zap"
    15  )
    16  
    17  const rootValidEndInc = 100
    18  
    19  // RelayCallback represents callback for sending validated state roots.
    20  type RelayCallback = func(*payload.Extensible)
    21  
    22  // AddSignature adds a state root signature.
    23  func (s *service) AddSignature(height uint32, validatorIndex int32, sig []byte) error {
    24  	if !s.MainCfg.Enabled {
    25  		return nil
    26  	}
    27  	myIndex, acc := s.getAccount()
    28  	if acc == nil {
    29  		return nil
    30  	}
    31  
    32  	incRoot := s.getIncompleteRoot(height, myIndex)
    33  	if incRoot == nil {
    34  		return nil
    35  	}
    36  
    37  	incRoot.Lock()
    38  	defer incRoot.Unlock()
    39  
    40  	if validatorIndex < 0 || int(validatorIndex) >= len(incRoot.svList) {
    41  		return errors.New("invalid validator index")
    42  	}
    43  
    44  	pub := incRoot.svList[validatorIndex]
    45  	if incRoot.root != nil {
    46  		ok := pub.VerifyHashable(sig, uint32(s.Network), incRoot.root)
    47  		if !ok {
    48  			return fmt.Errorf("invalid state root signature for %d", validatorIndex)
    49  		}
    50  	}
    51  	incRoot.addSignature(pub, sig)
    52  	s.trySendRoot(incRoot, acc)
    53  	return nil
    54  }
    55  
    56  // GetConfig returns service configuration.
    57  func (s *service) GetConfig() config.StateRoot {
    58  	return s.MainCfg
    59  }
    60  
    61  func (s *service) getIncompleteRoot(height uint32, myIndex byte) *incompleteRoot {
    62  	s.srMtx.Lock()
    63  	defer s.srMtx.Unlock()
    64  	if incRoot, ok := s.incompleteRoots[height]; ok {
    65  		return incRoot
    66  	}
    67  	incRoot := &incompleteRoot{
    68  		myIndex: int(myIndex),
    69  		svList:  s.GetStateValidators(height),
    70  		sigs:    make(map[string]*rootSig),
    71  	}
    72  	s.incompleteRoots[height] = incRoot
    73  	return incRoot
    74  }
    75  
    76  // trySendRoot attempts to finalize and send MPTRoot, it must be called with the ir locked.
    77  func (s *service) trySendRoot(ir *incompleteRoot, acc *wallet.Account) {
    78  	if !ir.isSenderNow() {
    79  		return
    80  	}
    81  	sr, ready := ir.finalize()
    82  	if ready {
    83  		err := s.AddStateRoot(sr)
    84  		if err != nil {
    85  			s.log.Error("can't add validated state root", zap.Error(err))
    86  		}
    87  		s.sendValidatedRoot(sr, acc)
    88  		ir.isSent = true
    89  	}
    90  }
    91  
    92  func (s *service) sendValidatedRoot(r *state.MPTRoot, acc *wallet.Account) {
    93  	w := io.NewBufBinWriter()
    94  	m := NewMessage(RootT, r)
    95  	m.EncodeBinary(w.BinWriter)
    96  	ep := &payload.Extensible{
    97  		Category:        Category,
    98  		ValidBlockStart: r.Index,
    99  		ValidBlockEnd:   r.Index + rootValidEndInc,
   100  		Sender:          acc.ScriptHash(),
   101  		Data:            w.Bytes(),
   102  		Witness: transaction.Witness{
   103  			VerificationScript: acc.GetVerificationScript(),
   104  		},
   105  	}
   106  	sig := acc.SignHashable(s.Network, ep)
   107  	buf := io.NewBufBinWriter()
   108  	emit.Bytes(buf.BinWriter, sig)
   109  	ep.Witness.InvocationScript = buf.Bytes()
   110  	s.relayExtensible(ep)
   111  }