neo-go/pkg/services/stateroot/signature.go

112 lines
2.6 KiB
Go
Raw Normal View History

2021-02-02 09:34:27 +00:00
package stateroot
import (
"sync"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
2021-02-02 09:34:27 +00:00
"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/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/network/payload"
2021-02-02 09:34:27 +00:00
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
)
type (
incompleteRoot struct {
sync.RWMutex
// svList is a list of state validator keys for this stateroot.
svList keys.PublicKeys
2021-02-02 09:34:27 +00:00
// isSent is true state root was already broadcasted.
isSent bool
// request is oracle request.
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.
retries int
2021-02-02 09:34:27 +00:00
}
rootSig struct {
// pub is cached public key.
pub *keys.PublicKey
// ok is true if signature was verified.
ok bool
// sig is state root signature.
sig []byte
}
)
func (r *incompleteRoot) reverify(net netmode.Magic) {
2021-02-02 09:34:27 +00:00
for _, sig := range r.sigs {
if !sig.ok {
sig.ok = sig.pub.VerifyHashable(sig.sig, uint32(net), r.root)
2021-02-02 09:34:27 +00:00
}
}
}
func (r *incompleteRoot) addSignature(pub *keys.PublicKey, sig []byte) {
r.sigs[string(pub.Bytes())] = &rootSig{
pub: pub,
ok: r.root != nil,
sig: sig,
}
}
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
}
2021-02-02 09:34:27 +00:00
// 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) {
2021-02-02 09:34:27 +00:00
if r.root == nil {
return nil, false
}
m := smartcontract.GetDefaultHonestNodeCount(len(r.svList))
2021-02-02 09:34:27 +00:00
sigs := make([][]byte, 0, m)
for _, pub := range r.svList {
2021-02-02 09:34:27 +00:00
sig, ok := r.sigs[string(pub.Bytes())]
if ok && sig.ok {
sigs = append(sigs, sig.sig)
if len(sigs) == m {
break
}
}
}
if len(sigs) != m {
return nil, false
}
verif, err := smartcontract.CreateDefaultMultiSigRedeemScript(r.svList)
if err != nil {
return nil, false
}
2021-02-02 09:34:27 +00:00
w := io.NewBufBinWriter()
for i := range sigs {
emit.Bytes(w.BinWriter, sigs[i])
}
r.root.Witness = []transaction.Witness{{
InvocationScript: w.Bytes(),
VerificationScript: verif,
}}
2021-02-02 09:34:27 +00:00
return r.root, true
}