neoneo-go/pkg/services/stateroot/network.go

113 lines
2.8 KiB
Go
Raw Normal View History

2021-02-02 09:34:27 +00:00
package stateroot
import (
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/network/payload"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/wallet"
2021-02-02 09:34:27 +00:00
"go.uber.org/zap"
)
const rootValidEndInc = 100
2021-02-02 09:34:27 +00:00
// RelayCallback represents callback for sending validated state roots.
type RelayCallback = func(*payload.Extensible)
// AddSignature adds state root signature.
func (s *service) AddSignature(height uint32, validatorIndex int32, sig []byte) error {
if !s.MainCfg.Enabled {
return nil
}
myIndex, acc := s.getAccount()
if acc == nil {
return nil
}
2021-02-02 09:34:27 +00:00
incRoot := s.getIncompleteRoot(height, myIndex)
2021-02-02 09:34:27 +00:00
if incRoot == nil {
return nil
}
incRoot.Lock()
defer incRoot.Unlock()
if validatorIndex < 0 || int(validatorIndex) >= len(incRoot.svList) {
return errors.New("invalid validator index")
}
pub := incRoot.svList[validatorIndex]
2021-02-02 09:34:27 +00:00
if incRoot.root != nil {
ok := pub.VerifyHashable(sig, uint32(s.Network), incRoot.root)
2021-02-02 09:34:27 +00:00
if !ok {
return fmt.Errorf("invalid state root signature for %d", validatorIndex)
}
}
incRoot.addSignature(pub, sig)
s.trySendRoot(incRoot, acc)
2021-02-02 09:34:27 +00:00
return nil
}
// GetConfig returns service configuration.
func (s *service) GetConfig() config.StateRoot {
return s.MainCfg
}
func (s *service) getIncompleteRoot(height uint32, myIndex byte) *incompleteRoot {
2021-02-02 09:34:27 +00:00
s.srMtx.Lock()
defer s.srMtx.Unlock()
if incRoot, ok := s.incompleteRoots[height]; ok {
return incRoot
}
incRoot := &incompleteRoot{
myIndex: int(myIndex),
svList: s.GetStateValidators(height),
sigs: make(map[string]*rootSig),
}
2021-02-02 09:34:27 +00:00
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.isSenderNow() {
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) {
priv := acc.PrivateKey()
2021-02-02 09:34:27 +00:00
w := io.NewBufBinWriter()
m := NewMessage(RootT, r)
2021-02-02 09:34:27 +00:00
m.EncodeBinary(w.BinWriter)
ep := &payload.Extensible{
Category: Category,
2021-02-02 09:34:27 +00:00
ValidBlockStart: r.Index,
ValidBlockEnd: r.Index + rootValidEndInc,
Sender: priv.GetScriptHash(),
2021-02-02 09:34:27 +00:00
Data: w.Bytes(),
Witness: transaction.Witness{
VerificationScript: acc.GetVerificationScript(),
},
2021-02-02 09:34:27 +00:00
}
sig := priv.SignHashable(uint32(s.Network), ep)
buf := io.NewBufBinWriter()
emit.Bytes(buf.BinWriter, sig)
ep.Witness.InvocationScript = buf.Bytes()
s.relayExtensible(ep)
2021-02-02 09:34:27 +00:00
}