Skip to content

Commit

Permalink
neotest: reuse wallet.Account for contract signers
Browse files Browse the repository at this point in the history
Refs #3245
Refs #3233

Signed-off-by: Evgenii Stratonikov <fyfyrchik@runbox.com>
  • Loading branch information
fyfyrchik committed Dec 8, 2023
1 parent c52566b commit 2076fda
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 54 deletions.
5 changes: 3 additions & 2 deletions pkg/neotest/basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,9 @@ func AddNetworkFee(t testing.TB, bc *core.Blockchain, tx *transaction.Transactio
baseFee := bc.GetBaseExecFee()
size := io.GetVarSize(tx)
for _, sgr := range signers {
if csgr, ok := sgr.(ContractSigner); ok {
sc, err := csgr.InvocationScript(tx)
csgr, ok := sgr.(SingleSigner)
if ok && csgr.Account().Contract.InvocationScript != nil {
sc, err := csgr.Account().Contract.InvocationScript(tx)
require.NoError(t, err)

txCopy := *tx
Expand Down
79 changes: 27 additions & 52 deletions pkg/neotest/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package neotest

import (
"bytes"
"errors"
"fmt"
"sort"
"testing"
Expand All @@ -11,6 +10,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
Expand Down Expand Up @@ -47,13 +47,6 @@ type MultiSigner interface {
Single(n int) SingleSigner
}

// ContractSigner is an interface for contract signer.
type ContractSigner interface {
Signer
// InvocationScript returns an invocation script to be used as invocation script for contract-based witness.
InvocationScript(tx *transaction.Transaction) ([]byte, error)
}

// signer represents a simple-signature signer.
type signer wallet.Account

Expand Down Expand Up @@ -190,31 +183,28 @@ func checkMultiSigner(t testing.TB, s Signer) {
}
}

type contractSigner struct {
params func(tx *transaction.Transaction) []any
scriptHash util.Uint160
}
type contractSigner wallet.Account

// NewContractSigner returns a contract signer for the provided contract hash.
// getInvParams must return params to be used as invocation script for contract-based witness.
func NewContractSigner(h util.Uint160, getInvParams func(tx *transaction.Transaction) []any) ContractSigner {
func NewContractSigner(h util.Uint160, getInvParams func(tx *transaction.Transaction) []any) SingleSigner {
return &contractSigner{
scriptHash: h,
params: getInvParams,
}
}

// InvocationScript implements ContractSigner.
func (s *contractSigner) InvocationScript(tx *transaction.Transaction) ([]byte, error) {
params := s.params(tx)
script := io.NewBufBinWriter()
for i := range params {
emit.Any(script.BinWriter, params[i])
}
if script.Err != nil {
return nil, script.Err
Address: address.Uint160ToString(h),
Contract: &wallet.Contract{
Deployed: true,
InvocationScript: func(tx *transaction.Transaction) ([]byte, error) {
params := getInvParams(tx)
script := io.NewBufBinWriter()
for i := range params {
emit.Any(script.BinWriter, params[i])
}
if script.Err != nil {
return nil, script.Err
}
return script.Bytes(), nil
},
},
}
return script.Bytes(), nil
}

// Script implements ContractSigner.
Expand All @@ -224,7 +214,12 @@ func (s *contractSigner) Script() []byte {

// ScriptHash implements ContractSigner.
func (s *contractSigner) ScriptHash() util.Uint160 {
return s.scriptHash
return s.Account().ScriptHash()
}

// ScriptHash implements ContractSigner.
func (s *contractSigner) Account() *wallet.Account {
return (*wallet.Account)(s)
}

// SignHashable implements ContractSigner.
Expand All @@ -234,27 +229,7 @@ func (s *contractSigner) SignHashable(uint32, hash.Hashable) []byte {

// SignTx implements ContractSigner.
func (s *contractSigner) SignTx(magic netmode.Magic, tx *transaction.Transaction) error {
pos := -1
for idx := range tx.Signers {
if tx.Signers[idx].Account.Equals(s.ScriptHash()) {
pos = idx
break
}
}
if pos < 0 {
return fmt.Errorf("signer %s not found", s.ScriptHash().String())
}
if len(tx.Scripts) < pos {
return errors.New("transaction is not yet signed by the previous signer")
}
invoc, err := s.InvocationScript(tx)
if err != nil {
return err
}
if len(tx.Scripts) == pos {
tx.Scripts = append(tx.Scripts, transaction.Witness{})
}
tx.Scripts[pos].InvocationScript = invoc
tx.Scripts[pos].VerificationScript = s.Script()
return nil
// Here we rely on `len(s.Contract.Parameters) == 0` being after the `s.Contract.InvocationScript != nil` check,
// because we cannot determine the list of parameters unless we already have tx.
return s.Account().SignTx(magic, tx)
}

0 comments on commit 2076fda

Please sign in to comment.