Skip to content

Commit

Permalink
notary: avoid changing pooled fallback transaction witnesses
Browse files Browse the repository at this point in the history
Forbid Notary service to change the fallback's witnesses in any way.
Fix the problem described in review comment:
#3098 (comment).

Signed-off-by: Anna Shaleva <[email protected]>
  • Loading branch information
AnnaShaleva committed Aug 29, 2023
1 parent b4dff7b commit c63289a
Showing 1 changed file with 23 additions and 7 deletions.
30 changes: 23 additions & 7 deletions pkg/services/notary/notary.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/network/payload"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/util/slice"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/wallet"
Expand Down Expand Up @@ -264,21 +265,21 @@ func (n *Notary) OnNewRequest(payload *payload.P2PNotaryRequest) {
} else {
// Avoid changes in the main transaction witnesses got from the notary request pool to
// keep the pooled tx valid. We will update its copy => the copy's size will be changed.
cp := *payload.MainTransaction
cp.Scripts = make([]transaction.Witness, len(payload.MainTransaction.Scripts))
copy(cp.Scripts, payload.MainTransaction.Scripts)
r = &request{
main: &cp,
main: safeCopy(payload.MainTransaction),
minNotValidBefore: nvbFallback,
}
n.requests[payload.MainTransaction.Hash()] = r
}
if r.witnessInfo == nil && validationErr == nil {
r.witnessInfo = newInfo
}
// Allow modification of a fallback transaction got from the notary request pool.
// It has dummy Notary witness attached => its size won't be changed.
r.fallbacks = append(r.fallbacks, payload.FallbackTransaction)
// Disallow modification of a fallback transaction got from the notary
// request pool. Even though it has dummy Notary witness attached and its
// size won't be changed after finalisation, the witness bytes changes may
// affect the other users of notary pool and cause race. Avoid this by making
// the copy.
r.fallbacks = append(r.fallbacks, safeCopy(payload.FallbackTransaction))
if exists && r.isMainCompleted() || validationErr != nil {
return
}
Expand Down Expand Up @@ -338,6 +339,21 @@ func (n *Notary) OnNewRequest(payload *payload.P2PNotaryRequest) {
}
}

// safeCopy creates a copy of provided transaction by dereferencing it and creating
// fresh witnesses so that the tx's witnesses may be modified without affecting the
// copy's ones.
func safeCopy(tx *transaction.Transaction) *transaction.Transaction {
cp := *tx
cp.Scripts = make([]transaction.Witness, len(tx.Scripts))
for i := range cp.Scripts {
cp.Scripts[i] = transaction.Witness{
InvocationScript: slice.Copy(tx.Scripts[i].InvocationScript),
VerificationScript: slice.Copy(tx.Scripts[i].VerificationScript),
}
}
return &cp
}

// OnRequestRemoval is a callback which is called after fallback transaction is removed
// from the notary payload pool due to expiration, main tx appliance or any other reason.
func (n *Notary) OnRequestRemoval(pld *payload.P2PNotaryRequest) {
Expand Down

0 comments on commit c63289a

Please sign in to comment.