services: refactor the logic of notary signatures counting

Maintain the number of signatures left to collect instead of maintaining
the number of already collected signatures and overall number of
signatures.
This commit is contained in:
Anna Shaleva 2021-10-20 17:35:37 +03:00
parent 6a40365e28
commit fcc7f7349d

View file

@ -77,13 +77,12 @@ type request struct {
// We stop trying to send mainTx to the network if the chain reaches minNotValidBefore height. // We stop trying to send mainTx to the network if the chain reaches minNotValidBefore height.
minNotValidBefore uint32 minNotValidBefore uint32
fallbacks []*transaction.Transaction fallbacks []*transaction.Transaction
// nSigs is the number of signatures to be collected. // nSigsLeft is the number of signatures left to collect to complete main transaction.
// nSigs == nKeys for standard signature request; // Initial nSigsLeft value is defined as following:
// nSigs <= nKeys for multisignature request. // nSigsLeft == nKeys for standard signature request;
// nSigs is 0 when all received requests were invalid, so check request.typ before access to nSigs. // nSigsLeft <= nKeys for multisignature request;
nSigs uint8 // nSigsLeft == 0 when all received requests were invalid, so check request.typ before access to nSigs.
// nSigsCollected is the number of already collected signatures nSigsLeft uint8
nSigsCollected uint8
// sigs is a map of partial multisig invocation scripts [opcode.PUSHDATA1+64+signatureBytes] grouped by public keys // sigs is a map of partial multisig invocation scripts [opcode.PUSHDATA1+64+signatureBytes] grouped by public keys
sigs map[*keys.PublicKey][]byte sigs map[*keys.PublicKey][]byte
@ -179,11 +178,11 @@ func (n *Notary) OnNewRequest(payload *payload.P2PNotaryRequest) {
} }
if r.typ == Unknown && validationErr == nil { if r.typ == Unknown && validationErr == nil {
r.typ = typ r.typ = typ
r.nSigs = nSigs r.nSigsLeft = nSigs
} }
} else { } else {
r = &request{ r = &request{
nSigs: nSigs, nSigsLeft: nSigs,
main: payload.MainTransaction, main: payload.MainTransaction,
typ: typ, typ: typ,
minNotValidBefore: nvbFallback, minNotValidBefore: nvbFallback,
@ -191,7 +190,7 @@ func (n *Notary) OnNewRequest(payload *payload.P2PNotaryRequest) {
n.requests[payload.MainTransaction.Hash()] = r n.requests[payload.MainTransaction.Hash()] = r
} }
r.fallbacks = append(r.fallbacks, payload.FallbackTransaction) r.fallbacks = append(r.fallbacks, payload.FallbackTransaction)
if exists && r.typ != Unknown && r.nSigsCollected >= r.nSigs { // already collected sufficient number of signatures to complete main transaction if exists && r.typ != Unknown && r.nSigsLeft == 0 { // already collected sufficient number of signatures to complete main transaction
return return
} }
if validationErr == nil { if validationErr == nil {
@ -204,12 +203,12 @@ func (n *Notary) OnNewRequest(payload *payload.P2PNotaryRequest) {
switch r.typ { switch r.typ {
case Signature: case Signature:
if !exists { if !exists {
r.nSigsCollected++ r.nSigsLeft--
} else if len(r.main.Scripts[i].InvocationScript) == 0 { // need this check because signature can already be added (consider receiving the same payload multiple times) } else if len(r.main.Scripts[i].InvocationScript) == 0 { // need this check because signature can already be added (consider receiving the same payload multiple times)
r.main.Scripts[i] = w r.main.Scripts[i] = w
r.nSigsCollected++ r.nSigsLeft--
} }
if r.nSigsCollected == r.nSigs { if r.nSigsLeft == 0 {
break loop break loop
} }
case MultiSignature: case MultiSignature:
@ -224,8 +223,8 @@ func (n *Notary) OnNewRequest(payload *payload.P2PNotaryRequest) {
} }
if pub.Verify(w.InvocationScript[2:], hash) { // then pub is the owner of the signature if pub.Verify(w.InvocationScript[2:], hash) { // then pub is the owner of the signature
r.sigs[pub] = w.InvocationScript r.sigs[pub] = w.InvocationScript
r.nSigsCollected++ r.nSigsLeft--
if r.nSigsCollected == r.nSigs { if r.nSigsLeft == 0 {
var invScript []byte var invScript []byte
for j := range pubs { for j := range pubs {
if sig, ok := r.sigs[pubs[j]]; ok { if sig, ok := r.sigs[pubs[j]]; ok {
@ -243,7 +242,7 @@ func (n *Notary) OnNewRequest(payload *payload.P2PNotaryRequest) {
} }
} }
} }
if r.typ != Unknown && r.nSigsCollected == nSigs && r.minNotValidBefore > n.Config.Chain.BlockHeight() { if r.typ != Unknown && r.nSigsLeft == 0 && r.minNotValidBefore > n.Config.Chain.BlockHeight() {
if err := n.finalize(acc, r.main, payload.MainTransaction.Hash()); err != nil { if err := n.finalize(acc, r.main, payload.MainTransaction.Hash()); err != nil {
n.Config.Log.Error("failed to finalize main transaction", zap.Error(err)) n.Config.Log.Error("failed to finalize main transaction", zap.Error(err))
} }
@ -286,7 +285,7 @@ func (n *Notary) PostPersist() {
defer n.reqMtx.Unlock() defer n.reqMtx.Unlock()
currHeight := n.Config.Chain.BlockHeight() currHeight := n.Config.Chain.BlockHeight()
for h, r := range n.requests { for h, r := range n.requests {
if !r.isSent && r.typ != Unknown && r.nSigs == r.nSigsCollected && r.minNotValidBefore > currHeight { if !r.isSent && r.typ != Unknown && r.nSigsLeft == 0 && r.minNotValidBefore > currHeight {
if err := n.finalize(acc, r.main, h); err != nil { if err := n.finalize(acc, r.main, h); err != nil {
n.Config.Log.Error("failed to finalize main transaction", zap.Error(err)) n.Config.Log.Error("failed to finalize main transaction", zap.Error(err))
} }