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 }