2021-12-03 11:17:37 +00:00
|
|
|
package tests
|
|
|
|
|
|
|
|
import (
|
2023-12-06 16:45:17 +00:00
|
|
|
"errors"
|
2021-12-03 11:17:37 +00:00
|
|
|
"path"
|
|
|
|
"testing"
|
|
|
|
|
2023-12-06 16:45:17 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
|
|
|
"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/io"
|
2021-12-03 11:17:37 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/neotest"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2023-12-06 16:45:17 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
2021-12-03 11:17:37 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
2023-12-06 16:45:17 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2021-12-03 11:17:37 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const proxyPath = "../proxy"
|
|
|
|
|
|
|
|
func deployProxyContract(t *testing.T, e *neotest.Executor, addrNetmap util.Uint160) util.Uint160 {
|
2023-11-07 12:18:48 +00:00
|
|
|
args := make([]any, 1)
|
2021-12-03 11:17:37 +00:00
|
|
|
args[0] = addrNetmap
|
|
|
|
|
|
|
|
c := neotest.CompileFile(t, e.CommitteeHash, proxyPath, path.Join(proxyPath, "config.yml"))
|
|
|
|
e.DeployContract(t, c, args)
|
|
|
|
return c.Hash
|
|
|
|
}
|
|
|
|
|
|
|
|
func newProxyInvoker(t *testing.T) *neotest.ContractInvoker {
|
|
|
|
e := newExecutor(t)
|
|
|
|
|
|
|
|
ctrNetmap := neotest.CompileFile(t, e.CommitteeHash, netmapPath, path.Join(netmapPath, "config.yml"))
|
|
|
|
ctrBalance := neotest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml"))
|
|
|
|
ctrContainer := neotest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml"))
|
|
|
|
ctrProxy := neotest.CompileFile(t, e.CommitteeHash, proxyPath, path.Join(proxyPath, "config.yml"))
|
|
|
|
|
|
|
|
deployNetmapContract(t, e, ctrBalance.Hash, ctrContainer.Hash)
|
|
|
|
deployProxyContract(t, e, ctrNetmap.Hash)
|
|
|
|
|
|
|
|
return e.CommitteeInvoker(ctrProxy.Hash)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestVerify(t *testing.T) {
|
|
|
|
e := newProxyInvoker(t)
|
2023-12-06 16:45:17 +00:00
|
|
|
acc := e.NewAccount(t)
|
2021-12-03 11:17:37 +00:00
|
|
|
|
2023-12-06 16:45:17 +00:00
|
|
|
gas := e.NewInvoker(e.NativeHash(t, nativenames.Gas), e.Validator)
|
|
|
|
gas.Invoke(t, true, "transfer", e.Validator.ScriptHash(), e.Hash, 100_0000_0000, nil)
|
2021-12-03 11:17:37 +00:00
|
|
|
|
2023-12-06 16:45:17 +00:00
|
|
|
t.Run("proxy + committee", func(t *testing.T) {
|
|
|
|
s := &proxySigner{contract: e.Hash, account: e.CommitteeHash}
|
|
|
|
tx := e.PrepareInvocation(t, []byte{byte(opcode.RET)}, []neotest.Signer{s, e.Committee})
|
|
|
|
require.NoError(t, e.Chain.VerifyTx(tx))
|
|
|
|
})
|
|
|
|
t.Run("proxy + custom account", func(t *testing.T) {
|
|
|
|
s := &proxySigner{contract: e.Hash, account: acc.ScriptHash()}
|
|
|
|
t.Run("bad, only proxy", func(t *testing.T) {
|
|
|
|
tx := e.PrepareInvocation(t, []byte{byte(opcode.RET)}, []neotest.Signer{s, acc})
|
|
|
|
require.Error(t, e.Chain.VerifyTx(tx))
|
|
|
|
})
|
2021-12-03 11:17:37 +00:00
|
|
|
|
2023-12-06 16:45:17 +00:00
|
|
|
e.Invoke(t, stackitem.Null{}, "addAccount", s.account)
|
2021-12-03 11:17:37 +00:00
|
|
|
|
2023-12-06 16:45:17 +00:00
|
|
|
tx := e.PrepareInvocation(t, []byte{byte(opcode.RET)}, []neotest.Signer{s, acc})
|
|
|
|
require.NoError(t, e.Chain.VerifyTx(tx))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
type proxySigner struct {
|
|
|
|
contract util.Uint160
|
|
|
|
account util.Uint160
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ neotest.ContractSigner = (*proxySigner)(nil)
|
|
|
|
|
|
|
|
func (s *proxySigner) Script() []byte {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func (s *proxySigner) ScriptHash() util.Uint160 {
|
|
|
|
return s.contract
|
|
|
|
}
|
|
|
|
func (s *proxySigner) SignHashable(uint32, hash.Hashable) []byte {
|
|
|
|
panic("not implemented")
|
|
|
|
}
|
|
|
|
func (s *proxySigner) SignTx(_ netmode.Magic, tx *transaction.Transaction) error {
|
|
|
|
pos := -1
|
|
|
|
for i := range tx.Signers {
|
|
|
|
if tx.Signers[i].Account.Equals(s.contract) {
|
|
|
|
pos = i
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if pos < 0 {
|
|
|
|
return errors.New("transaction is not signed by this account")
|
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
w := transaction.Witness{InvocationScript: invoc}
|
|
|
|
if len(tx.Scripts) == pos {
|
|
|
|
tx.Scripts = append(tx.Scripts, w)
|
|
|
|
} else {
|
|
|
|
tx.Scripts[pos].InvocationScript = invoc
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func (s *proxySigner) InvocationScript(tx *transaction.Transaction) ([]byte, error) {
|
|
|
|
w := io.NewBufBinWriter()
|
|
|
|
emit.Any(w.BinWriter, s.account)
|
|
|
|
return w.Bytes(), nil
|
2021-12-03 11:17:37 +00:00
|
|
|
}
|