neotest: add contract client wrapper
Reduces amount of boilerplate code in tests. Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
e3625152c6
commit
1f9fd4a472
3 changed files with 276 additions and 226 deletions
|
@ -6,21 +6,16 @@ import (
|
||||||
|
|
||||||
nns "github.com/nspcc-dev/neo-go/examples/nft-nd-nns"
|
nns "github.com/nspcc-dev/neo-go/examples/nft-nd-nns"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neotest"
|
"github.com/nspcc-dev/neo-go/pkg/neotest"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
|
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newExecutorWithNS(t *testing.T) (*neotest.Executor, util.Uint160) {
|
func newNSClient(t *testing.T) *neotest.ContractInvoker {
|
||||||
bc, acc := chain.NewSingle(t)
|
bc, acc := chain.NewSingle(t)
|
||||||
e := neotest.NewExecutor(t, bc, acc)
|
e := neotest.NewExecutor(t, bc, acc)
|
||||||
c := neotest.CompileFile(t, e.CommitteeHash, "..", "../nns.yml")
|
c := neotest.CompileFile(t, e.CommitteeHash, "..", "../nns.yml")
|
||||||
|
@ -29,85 +24,113 @@ func newExecutorWithNS(t *testing.T) (*neotest.Executor, util.Uint160) {
|
||||||
h, err := e.Chain.GetContractScriptHash(1)
|
h, err := e.Chain.GetContractScriptHash(1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, c.Hash, h)
|
require.Equal(t, c.Hash, h)
|
||||||
return e, c.Hash
|
return e.CommitteeInvoker(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
func TestNameService_Price(t *testing.T) {
|
||||||
//func TestNameService_Price(t *testing.T) {
|
const (
|
||||||
// e, nsHash := newExecutorWithNS(t)
|
minPrice = int64(0)
|
||||||
//
|
maxPrice = int64(10000_00000000)
|
||||||
// testGetSet(t, e.Chain, nsHash, "Price",
|
)
|
||||||
// defaultNameServiceDomainPrice, 0, 10000_00000000)
|
|
||||||
//}
|
c := newNSClient(t)
|
||||||
|
|
||||||
|
t.Run("set, not signed by committee", func(t *testing.T) {
|
||||||
|
acc := c.NewAccount(t)
|
||||||
|
cAcc := c.WithSigner(acc)
|
||||||
|
cAcc.InvokeFail(t, "not witnessed by committee", "setPrice", minPrice+1)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("get, default value", func(t *testing.T) {
|
||||||
|
c.Invoke(t, defaultNameServiceDomainPrice, "getPrice")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("set, too small value", func(t *testing.T) {
|
||||||
|
c.InvokeFail(t, "The price is out of range.", "setPrice", minPrice-1)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("set, too large value", func(t *testing.T) {
|
||||||
|
c.InvokeFail(t, "The price is out of range.", "setPrice", maxPrice+1)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("set, success", func(t *testing.T) {
|
||||||
|
txSet := c.PrepareInvoke(t, "setPrice", int64(defaultNameServiceDomainPrice+1))
|
||||||
|
txGet := c.PrepareInvoke(t, "getPrice")
|
||||||
|
c.AddBlockCheckHalt(t, txSet, txGet)
|
||||||
|
c.CheckHalt(t, txSet.Hash(), stackitem.Null{})
|
||||||
|
c.CheckHalt(t, txGet.Hash(), stackitem.Make(defaultNameServiceDomainPrice+1))
|
||||||
|
|
||||||
|
// Get in the next block.
|
||||||
|
c.Invoke(t, stackitem.Make(defaultNameServiceDomainPrice+1), "getPrice")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestNonfungible(t *testing.T) {
|
func TestNonfungible(t *testing.T) {
|
||||||
e, nsHash := newExecutorWithNS(t)
|
c := newNSClient(t)
|
||||||
|
|
||||||
acc := e.NewAccount(t)
|
c.Signer = c.NewAccount(t)
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, acc, "symbol", "NNS")
|
c.Invoke(t, "NNS", "symbol")
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, acc, "decimals", 0)
|
c.Invoke(t, 0, "decimals")
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, acc, "totalSupply", 0)
|
c.Invoke(t, 0, "totalSupply")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddRoot(t *testing.T) {
|
func TestAddRoot(t *testing.T) {
|
||||||
e, nsHash := newExecutorWithNS(t)
|
c := newNSClient(t)
|
||||||
|
|
||||||
t.Run("invalid format", func(t *testing.T) {
|
t.Run("invalid format", func(t *testing.T) {
|
||||||
testNameServiceInvoke(t, e, nsHash, "addRoot", nil, "")
|
c.InvokeFail(t, "invalid root format", "addRoot", "")
|
||||||
})
|
})
|
||||||
t.Run("not signed by committee", func(t *testing.T) {
|
t.Run("not signed by committee", func(t *testing.T) {
|
||||||
acc := e.NewAccount(t)
|
acc := c.NewAccount(t)
|
||||||
tx := e.PrepareInvoke(t, acc, nsHash, "addRoot", "some")
|
c := c.WithSigner(acc)
|
||||||
e.AddBlock(t, tx)
|
c.InvokeFail(t, "not witnessed by committee", "addRoot", "some")
|
||||||
e.CheckFault(t, tx.Hash(), "not witnessed by committee")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
testNameServiceInvoke(t, e, nsHash, "addRoot", stackitem.Null{}, "some")
|
c.Invoke(t, stackitem.Null{}, "addRoot", "some")
|
||||||
t.Run("already exists", func(t *testing.T) {
|
t.Run("already exists", func(t *testing.T) {
|
||||||
testNameServiceInvoke(t, e, nsHash, "addRoot", nil, "some")
|
c.InvokeFail(t, "already exists", "addRoot", "some")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExpiration(t *testing.T) {
|
func TestExpiration(t *testing.T) {
|
||||||
e, nsHash := newExecutorWithNS(t)
|
c := newNSClient(t)
|
||||||
|
e := c.Executor
|
||||||
bc := e.Chain
|
bc := e.Chain
|
||||||
|
|
||||||
acc := e.NewAccount(t)
|
acc := e.NewAccount(t)
|
||||||
|
cAcc := c.WithSigner(acc)
|
||||||
|
|
||||||
testNameServiceInvoke(t, e, nsHash, "addRoot", stackitem.Null{}, "com")
|
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, acc, "register",
|
cAcc.Invoke(t, true, "register", "first.com", acc.Contract.ScriptHash())
|
||||||
true, "first.com", acc.Contract.ScriptHash())
|
cAcc.Invoke(t, stackitem.Null{}, "setRecord", "first.com", int64(nns.TXT), "sometext")
|
||||||
|
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, acc,
|
|
||||||
"setRecord", stackitem.Null{}, "first.com", int64(nns.TXT), "sometext")
|
|
||||||
b1 := e.TopBlock(t)
|
b1 := e.TopBlock(t)
|
||||||
|
|
||||||
tx := e.PrepareInvoke(t, acc, nsHash, "register", "second.com", acc.Contract.ScriptHash())
|
tx := cAcc.PrepareInvoke(t, "register", "second.com", acc.Contract.ScriptHash())
|
||||||
b2 := e.NewBlock(t, tx)
|
b2 := e.NewUnsignedBlock(t, tx)
|
||||||
b2.Index = b1.Index + 1
|
b2.Index = b1.Index + 1
|
||||||
b2.PrevHash = b1.Hash()
|
b2.PrevHash = b1.Hash()
|
||||||
b2.Timestamp = b1.Timestamp + 10000
|
b2.Timestamp = b1.Timestamp + 10000
|
||||||
require.NoError(t, bc.AddBlock(e.SignBlock(b2)))
|
require.NoError(t, bc.AddBlock(e.SignBlock(b2)))
|
||||||
e.CheckHalt(t, tx.Hash())
|
e.CheckHalt(t, tx.Hash())
|
||||||
|
|
||||||
tx = e.PrepareInvoke(t, acc, nsHash, "isAvailable", "first.com")
|
tx = cAcc.PrepareInvoke(t, "isAvailable", "first.com")
|
||||||
b3 := e.NewBlock(t, tx)
|
b3 := e.NewUnsignedBlock(t, tx)
|
||||||
b3.Index = b2.Index + 1
|
b3.Index = b2.Index + 1
|
||||||
b3.PrevHash = b2.Hash()
|
b3.PrevHash = b2.Hash()
|
||||||
b3.Timestamp = b1.Timestamp + (millisecondsInYear + 1)
|
b3.Timestamp = b1.Timestamp + (millisecondsInYear + 1)
|
||||||
require.NoError(t, bc.AddBlock(e.SignBlock(b3)))
|
require.NoError(t, bc.AddBlock(e.SignBlock(b3)))
|
||||||
e.CheckHalt(t, tx.Hash(), stackitem.NewBool(true))
|
e.CheckHalt(t, tx.Hash(), stackitem.NewBool(true))
|
||||||
|
|
||||||
tx = e.PrepareInvoke(t, acc, nsHash, "isAvailable", "second.com")
|
tx = cAcc.PrepareInvoke(t, "isAvailable", "second.com")
|
||||||
b4 := e.NewBlock(t, tx)
|
b4 := e.NewUnsignedBlock(t, tx)
|
||||||
b4.Index = b3.Index + 1
|
b4.Index = b3.Index + 1
|
||||||
b4.PrevHash = b3.Hash()
|
b4.PrevHash = b3.Hash()
|
||||||
b4.Timestamp = b3.Timestamp + 1000
|
b4.Timestamp = b3.Timestamp + 1000
|
||||||
require.NoError(t, bc.AddBlock(e.SignBlock(b4)))
|
require.NoError(t, bc.AddBlock(e.SignBlock(b4)))
|
||||||
e.CheckHalt(t, tx.Hash(), stackitem.NewBool(false))
|
e.CheckHalt(t, tx.Hash(), stackitem.NewBool(false))
|
||||||
|
|
||||||
tx = e.PrepareInvoke(t, acc, nsHash, "getRecord", "first.com", int64(nns.TXT))
|
tx = cAcc.PrepareInvoke(t, "getRecord", "first.com", int64(nns.TXT))
|
||||||
b5 := e.NewBlock(t, tx)
|
b5 := e.NewUnsignedBlock(t, tx)
|
||||||
b5.Index = b4.Index + 1
|
b5.Index = b4.Index + 1
|
||||||
b5.PrevHash = b4.Hash()
|
b5.PrevHash = b4.Hash()
|
||||||
b5.Timestamp = b4.Timestamp + 1000
|
b5.Timestamp = b4.Timestamp + 1000
|
||||||
|
@ -118,90 +141,87 @@ func TestExpiration(t *testing.T) {
|
||||||
const millisecondsInYear = 365 * 24 * 3600 * 1000
|
const millisecondsInYear = 365 * 24 * 3600 * 1000
|
||||||
|
|
||||||
func TestRegisterAndRenew(t *testing.T) {
|
func TestRegisterAndRenew(t *testing.T) {
|
||||||
e, nsHash := newExecutorWithNS(t)
|
c := newNSClient(t)
|
||||||
|
e := c.Executor
|
||||||
|
|
||||||
testNameServiceInvoke(t, e, nsHash, "isAvailable", nil, "neo.com")
|
c.InvokeFail(t, "root not found", "isAvailable", "neo.com")
|
||||||
testNameServiceInvoke(t, e, nsHash, "addRoot", stackitem.Null{}, "org")
|
c.Invoke(t, stackitem.Null{}, "addRoot", "org")
|
||||||
testNameServiceInvoke(t, e, nsHash, "isAvailable", nil, "neo.com")
|
c.InvokeFail(t, "root not found", "isAvailable", "neo.com")
|
||||||
testNameServiceInvoke(t, e, nsHash, "addRoot", stackitem.Null{}, "com")
|
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||||
testNameServiceInvoke(t, e, nsHash, "isAvailable", true, "neo.com")
|
c.Invoke(t, true, "isAvailable", "neo.com")
|
||||||
testNameServiceInvoke(t, e, nsHash, "register", nil, "neo.org", e.CommitteeHash)
|
c.InvokeWithFeeFail(t, "GAS limit exceeded", defaultNameServiceSysfee, "register", "neo.org", e.CommitteeHash)
|
||||||
testNameServiceInvoke(t, e, nsHash, "register", nil, "docs.neo.org", e.CommitteeHash)
|
c.InvokeFail(t, "invalid domain name format", "register", "docs.neo.org", e.CommitteeHash)
|
||||||
testNameServiceInvoke(t, e, nsHash, "register", nil, "\nneo.com'", e.CommitteeHash)
|
c.InvokeFail(t, "invalid domain name format", "register", "\nneo.com'", e.CommitteeHash)
|
||||||
testNameServiceInvoke(t, e, nsHash, "register", nil, "neo.com\n", e.CommitteeHash)
|
c.InvokeFail(t, "invalid domain name format", "register", "neo.com\n", e.CommitteeHash)
|
||||||
testNameServiceInvoke(t, e, nsHash, "register", nil, "neo.com", e.CommitteeHash)
|
c.InvokeWithFeeFail(t, "GAS limit exceeded", defaultNameServiceSysfee, "register", "neo.org", e.CommitteeHash)
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceDomainPrice, e.Committee, "register",
|
c.InvokeWithFeeFail(t, "GAS limit exceeded", defaultNameServiceDomainPrice, "register", "neo.com", e.CommitteeHash)
|
||||||
nil, "neo.com", e.CommitteeHash)
|
|
||||||
|
|
||||||
testNameServiceInvoke(t, e, nsHash, "isAvailable", true, "neo.com")
|
c.Invoke(t, true, "isAvailable", "neo.com")
|
||||||
testNameServiceInvoke(t, e, nsHash, "balanceOf", 0, e.CommitteeHash)
|
c.Invoke(t, 0, "balanceOf", e.CommitteeHash)
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, e.Committee, "register",
|
c.Invoke(t, true, "register", "neo.com", e.CommitteeHash)
|
||||||
true, "neo.com", e.CommitteeHash)
|
|
||||||
topBlock := e.TopBlock(t)
|
topBlock := e.TopBlock(t)
|
||||||
expectedExpiration := topBlock.Timestamp + millisecondsInYear
|
expectedExpiration := topBlock.Timestamp + millisecondsInYear
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, e.Committee, "register",
|
c.Invoke(t, false, "register", "neo.com", e.CommitteeHash)
|
||||||
false, "neo.com", e.CommitteeHash)
|
c.Invoke(t, false, "isAvailable", "neo.com")
|
||||||
testNameServiceInvoke(t, e, nsHash, "isAvailable", false, "neo.com")
|
|
||||||
|
|
||||||
props := stackitem.NewMap()
|
props := stackitem.NewMap()
|
||||||
props.Add(stackitem.Make("name"), stackitem.Make("neo.com"))
|
props.Add(stackitem.Make("name"), stackitem.Make("neo.com"))
|
||||||
props.Add(stackitem.Make("expiration"), stackitem.Make(expectedExpiration))
|
props.Add(stackitem.Make("expiration"), stackitem.Make(expectedExpiration))
|
||||||
testNameServiceInvoke(t, e, nsHash, "properties", props, "neo.com")
|
c.Invoke(t, props, "properties", "neo.com")
|
||||||
testNameServiceInvoke(t, e, nsHash, "balanceOf", 1, e.CommitteeHash)
|
c.Invoke(t, 1, "balanceOf", e.CommitteeHash)
|
||||||
testNameServiceInvoke(t, e, nsHash, "ownerOf", e.CommitteeHash.BytesBE(), []byte("neo.com"))
|
c.Invoke(t, e.CommitteeHash.BytesBE(), "ownerOf", []byte("neo.com"))
|
||||||
|
|
||||||
t.Run("invalid token ID", func(t *testing.T) {
|
t.Run("invalid token ID", func(t *testing.T) {
|
||||||
testNameServiceInvoke(t, e, nsHash, "properties", nil, "not.exists")
|
c.InvokeFail(t, "token not found", "properties", "not.exists")
|
||||||
testNameServiceInvoke(t, e, nsHash, "ownerOf", nil, "not.exists")
|
c.InvokeFail(t, "token not found", "ownerOf", "not.exists")
|
||||||
testNameServiceInvoke(t, e, nsHash, "properties", nil, []interface{}{})
|
c.InvokeFail(t, "invalid conversion", "properties", []interface{}{})
|
||||||
testNameServiceInvoke(t, e, nsHash, "ownerOf", nil, []interface{}{})
|
c.InvokeFail(t, "invalid conversion", "ownerOf", []interface{}{})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Renew
|
// Renew
|
||||||
expectedExpiration += millisecondsInYear
|
expectedExpiration += millisecondsInYear
|
||||||
testNameServiceInvokeAux(t, e, nsHash, 100_0000_0000, e.Committee, "renew", expectedExpiration, "neo.com")
|
c.Invoke(t, expectedExpiration, "renew", "neo.com")
|
||||||
|
|
||||||
props.Add(stackitem.Make("expiration"), stackitem.Make(expectedExpiration))
|
props.Add(stackitem.Make("expiration"), stackitem.Make(expectedExpiration))
|
||||||
testNameServiceInvoke(t, e, nsHash, "properties", props, "neo.com")
|
c.Invoke(t, props, "properties", "neo.com")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetGetRecord(t *testing.T) {
|
func TestSetGetRecord(t *testing.T) {
|
||||||
e, nsHash := newExecutorWithNS(t)
|
c := newNSClient(t)
|
||||||
|
e := c.Executor
|
||||||
|
|
||||||
acc := e.NewAccount(t)
|
acc := e.NewAccount(t)
|
||||||
testNameServiceInvoke(t, e, nsHash, "addRoot", stackitem.Null{}, "com")
|
cAcc := c.WithSigner(acc)
|
||||||
|
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||||
|
|
||||||
t.Run("set before register", func(t *testing.T) {
|
t.Run("set before register", func(t *testing.T) {
|
||||||
testNameServiceInvoke(t, e, nsHash, "setRecord", nil, "neo.com", int64(nns.TXT), "sometext")
|
c.InvokeFail(t, "token not found", "setRecord", "neo.com", int64(nns.TXT), "sometext")
|
||||||
})
|
})
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, e.Committee, "register",
|
c.Invoke(t, true, "register", "neo.com", e.CommitteeHash)
|
||||||
true, "neo.com", e.CommitteeHash)
|
|
||||||
t.Run("invalid parameters", func(t *testing.T) {
|
t.Run("invalid parameters", func(t *testing.T) {
|
||||||
testNameServiceInvoke(t, e, nsHash, "setRecord", nil, "neo.com", int64(0xFF), "1.2.3.4")
|
c.InvokeFail(t, "unsupported record type", "setRecord", "neo.com", int64(0xFF), "1.2.3.4")
|
||||||
testNameServiceInvoke(t, e, nsHash, "setRecord", nil, "neo.com", int64(nns.A), "not.an.ip.address")
|
c.InvokeFail(t, "invalid record", "setRecord", "neo.com", int64(nns.A), "not.an.ip.address")
|
||||||
})
|
})
|
||||||
t.Run("invalid witness", func(t *testing.T) {
|
t.Run("invalid witness", func(t *testing.T) {
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, acc, "setRecord", nil,
|
cAcc.InvokeFail(t, "not witnessed by admin", "setRecord", "neo.com", int64(nns.A), "1.2.3.4")
|
||||||
"neo.com", int64(nns.A), "1.2.3.4")
|
|
||||||
})
|
})
|
||||||
testNameServiceInvoke(t, e, nsHash, "getRecord", stackitem.Null{}, "neo.com", int64(nns.A))
|
c.Invoke(t, stackitem.Null{}, "getRecord", "neo.com", int64(nns.A))
|
||||||
testNameServiceInvoke(t, e, nsHash, "setRecord", stackitem.Null{}, "neo.com", int64(nns.A), "1.2.3.4")
|
c.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.A), "1.2.3.4")
|
||||||
testNameServiceInvoke(t, e, nsHash, "getRecord", "1.2.3.4", "neo.com", int64(nns.A))
|
c.Invoke(t, "1.2.3.4", "getRecord", "neo.com", int64(nns.A))
|
||||||
testNameServiceInvoke(t, e, nsHash, "setRecord", stackitem.Null{}, "neo.com", int64(nns.A), "1.2.3.4")
|
c.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.A), "1.2.3.4")
|
||||||
testNameServiceInvoke(t, e, nsHash, "getRecord", "1.2.3.4", "neo.com", int64(nns.A))
|
c.Invoke(t, "1.2.3.4", "getRecord", "neo.com", int64(nns.A))
|
||||||
testNameServiceInvoke(t, e, nsHash, "setRecord", stackitem.Null{}, "neo.com", int64(nns.AAAA), "2001:0201:1f1f:0000:0000:0100:11a0:11df")
|
c.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.AAAA), "2001:0201:1f1f:0000:0000:0100:11a0:11df")
|
||||||
testNameServiceInvoke(t, e, nsHash, "setRecord", stackitem.Null{}, "neo.com", int64(nns.CNAME), "nspcc.ru")
|
c.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.CNAME), "nspcc.ru")
|
||||||
testNameServiceInvoke(t, e, nsHash, "setRecord", stackitem.Null{}, "neo.com", int64(nns.TXT), "sometext")
|
c.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.TXT), "sometext")
|
||||||
|
|
||||||
// Delete record.
|
// Delete record.
|
||||||
t.Run("invalid witness", func(t *testing.T) {
|
t.Run("invalid witness", func(t *testing.T) {
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, acc, "setRecord", nil,
|
cAcc.InvokeFail(t, "not witnessed by admin", "deleteRecord", "neo.com", int64(nns.CNAME))
|
||||||
"neo.com", int64(nns.CNAME))
|
|
||||||
})
|
})
|
||||||
testNameServiceInvoke(t, e, nsHash, "getRecord", "nspcc.ru", "neo.com", int64(nns.CNAME))
|
c.Invoke(t, "nspcc.ru", "getRecord", "neo.com", int64(nns.CNAME))
|
||||||
testNameServiceInvoke(t, e, nsHash, "deleteRecord", stackitem.Null{}, "neo.com", int64(nns.CNAME))
|
c.Invoke(t, stackitem.Null{}, "deleteRecord", "neo.com", int64(nns.CNAME))
|
||||||
testNameServiceInvoke(t, e, nsHash, "getRecord", stackitem.Null{}, "neo.com", int64(nns.CNAME))
|
c.Invoke(t, stackitem.Null{}, "getRecord", "neo.com", int64(nns.CNAME))
|
||||||
testNameServiceInvoke(t, e, nsHash, "getRecord", "1.2.3.4", "neo.com", int64(nns.A))
|
c.Invoke(t, "1.2.3.4", "getRecord", "neo.com", int64(nns.A))
|
||||||
|
|
||||||
t.Run("SetRecord_compatibility", func(t *testing.T) {
|
t.Run("SetRecord_compatibility", func(t *testing.T) {
|
||||||
// tests are got from the NNS C# implementation and changed accordingly to non-native implementation behaviour
|
// tests are got from the NNS C# implementation and changed accordingly to non-native implementation behaviour
|
||||||
|
@ -258,206 +278,153 @@ func TestSetGetRecord(t *testing.T) {
|
||||||
{Type: nns.AAAA, Name: "2001::13.1.68.3", ShouldFail: true},
|
{Type: nns.AAAA, Name: "2001::13.1.68.3", ShouldFail: true},
|
||||||
}
|
}
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
var expected interface{}
|
args := []interface{}{"neo.com", int64(testCase.Type), testCase.Name}
|
||||||
if testCase.ShouldFail {
|
|
||||||
expected = nil
|
|
||||||
} else {
|
|
||||||
expected = stackitem.Null{}
|
|
||||||
}
|
|
||||||
t.Run(testCase.Name, func(t *testing.T) {
|
t.Run(testCase.Name, func(t *testing.T) {
|
||||||
testNameServiceInvoke(t, e, nsHash, "setRecord", expected, "neo.com", int64(testCase.Type), testCase.Name)
|
if testCase.ShouldFail {
|
||||||
|
c.InvokeFail(t, "", "setRecord", args...)
|
||||||
|
} else {
|
||||||
|
c.Invoke(t, stackitem.Null{}, "setRecord", args...)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetAdmin(t *testing.T) {
|
func TestSetAdmin(t *testing.T) {
|
||||||
e, nsHash := newExecutorWithNS(t)
|
c := newNSClient(t)
|
||||||
|
e := c.Executor
|
||||||
|
|
||||||
owner := e.NewAccount(t)
|
owner := e.NewAccount(t)
|
||||||
|
cOwner := c.WithSigner(owner)
|
||||||
admin := e.NewAccount(t)
|
admin := e.NewAccount(t)
|
||||||
|
cAdmin := c.WithSigner(admin)
|
||||||
guest := e.NewAccount(t)
|
guest := e.NewAccount(t)
|
||||||
testNameServiceInvoke(t, e, nsHash, "addRoot", stackitem.Null{}, "com")
|
cGuest := c.WithSigner(guest)
|
||||||
|
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, owner, "register", true,
|
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||||
"neo.com", owner.PrivateKey().GetScriptHash())
|
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, guest, "setAdmin", nil,
|
cOwner.Invoke(t, true, "register", "neo.com", owner.PrivateKey().GetScriptHash())
|
||||||
"neo.com", admin.PrivateKey().GetScriptHash())
|
cGuest.InvokeFail(t, "not witnessed", "setAdmin", "neo.com", admin.PrivateKey().GetScriptHash())
|
||||||
|
|
||||||
// Must be witnessed by both owner and admin.
|
// Must be witnessed by both owner and admin.
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, owner, "setAdmin", nil,
|
cOwner.InvokeFail(t, "not witnessed by admin", "setAdmin", "neo.com", admin.PrivateKey().GetScriptHash())
|
||||||
"neo.com", admin.PrivateKey().GetScriptHash())
|
cAdmin.InvokeFail(t, "not witnessed by owner", "setAdmin", "neo.com", admin.PrivateKey().GetScriptHash())
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, admin, "setAdmin", nil,
|
cc := c.WithSigner([]*wallet.Account{owner, admin})
|
||||||
"neo.com", admin.PrivateKey().GetScriptHash())
|
cc.Invoke(t, stackitem.Null{}, "setAdmin", "neo.com", admin.PrivateKey().GetScriptHash())
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, []*wallet.Account{owner, admin},
|
|
||||||
"setAdmin", stackitem.Null{},
|
|
||||||
"neo.com", admin.PrivateKey().GetScriptHash())
|
|
||||||
|
|
||||||
t.Run("set and delete by admin", func(t *testing.T) {
|
t.Run("set and delete by admin", func(t *testing.T) {
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, admin, "setRecord", stackitem.Null{},
|
cAdmin.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.TXT), "sometext")
|
||||||
"neo.com", int64(nns.TXT), "sometext")
|
cGuest.InvokeFail(t, "not witnessed by admin", "deleteRecord", "neo.com", int64(nns.TXT))
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, guest, "deleteRecord", nil,
|
cAdmin.Invoke(t, stackitem.Null{}, "deleteRecord", "neo.com", int64(nns.TXT))
|
||||||
"neo.com", int64(nns.TXT))
|
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, admin, "deleteRecord", stackitem.Null{},
|
|
||||||
"neo.com", int64(nns.TXT))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("set admin to null", func(t *testing.T) {
|
t.Run("set admin to null", func(t *testing.T) {
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, admin, "setRecord", stackitem.Null{},
|
cAdmin.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.TXT), "sometext")
|
||||||
"neo.com", int64(nns.TXT), "sometext")
|
cOwner.Invoke(t, stackitem.Null{}, "setAdmin", "neo.com", nil)
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, owner, "setAdmin", stackitem.Null{},
|
cAdmin.InvokeFail(t, "not witnessed by admin", "deleteRecord", "neo.com", int64(nns.TXT))
|
||||||
"neo.com", nil)
|
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, admin, "deleteRecord", nil,
|
|
||||||
"neo.com", int64(nns.TXT))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransfer(t *testing.T) {
|
func TestTransfer(t *testing.T) {
|
||||||
e, nsHash := newExecutorWithNS(t)
|
c := newNSClient(t)
|
||||||
|
e := c.Executor
|
||||||
|
|
||||||
from := e.NewAccount(t)
|
from := e.NewAccount(t)
|
||||||
|
cFrom := c.WithSigner(from)
|
||||||
to := e.NewAccount(t)
|
to := e.NewAccount(t)
|
||||||
|
cTo := c.WithSigner(to)
|
||||||
|
|
||||||
testNameServiceInvoke(t, e, nsHash, "addRoot", stackitem.Null{}, "com")
|
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, from, "register",
|
cFrom.Invoke(t, true, "register", "neo.com", from.PrivateKey().GetScriptHash())
|
||||||
true, "neo.com", from.PrivateKey().GetScriptHash())
|
cFrom.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.A), "1.2.3.4")
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, from, "setRecord", stackitem.Null{},
|
cFrom.InvokeFail(t, "token not found", "transfer", to.Contract.ScriptHash(), "not.exists", nil)
|
||||||
"neo.com", int64(nns.A), "1.2.3.4")
|
c.Invoke(t, false, "transfer", to.Contract.ScriptHash(), "neo.com", nil)
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, from, "transfer",
|
cFrom.Invoke(t, true, "transfer", to.Contract.ScriptHash(), "neo.com", nil)
|
||||||
nil, to.Contract.ScriptHash().BytesBE(), []byte("not.exists"), nil)
|
cFrom.Invoke(t, 1, "totalSupply")
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, e.Committee, "transfer",
|
cFrom.Invoke(t, to.Contract.ScriptHash().BytesBE(), "ownerOf", "neo.com")
|
||||||
false, to.Contract.ScriptHash().BytesBE(), []byte("neo.com"), nil)
|
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, from, "transfer",
|
|
||||||
true, to.Contract.ScriptHash().BytesBE(), []byte("neo.com"), nil)
|
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, from, "totalSupply", 1)
|
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, from, "ownerOf",
|
|
||||||
to.Contract.ScriptHash().BytesBE(), []byte("neo.com"))
|
|
||||||
|
|
||||||
// without onNEP11Transfer
|
// without onNEP11Transfer
|
||||||
c := neotest.CompileSource(t, e.CommitteeHash,
|
ctr := neotest.CompileSource(t, e.CommitteeHash,
|
||||||
strings.NewReader(`package foo
|
strings.NewReader(`package foo
|
||||||
func Main() int { return 0 }`),
|
func Main() int { return 0 }`),
|
||||||
&compiler.Options{Name: "foo"})
|
&compiler.Options{Name: "foo"})
|
||||||
e.DeployContract(t, c, nil)
|
e.DeployContract(t, ctr, nil)
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, to, "transfer",
|
cTo.InvokeFail(t, "method not found", "transfer", ctr.Hash, []byte("neo.com"), nil)
|
||||||
nil, c.Hash.BytesBE(), []byte("neo.com"), nil)
|
|
||||||
|
|
||||||
// with onNEP11Transfer
|
// with onNEP11Transfer
|
||||||
c = neotest.CompileSource(t, e.CommitteeHash,
|
ctr = neotest.CompileSource(t, e.CommitteeHash,
|
||||||
strings.NewReader(`package foo
|
strings.NewReader(`package foo
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
func OnNEP11Payment(from interop.Hash160, amount int, token []byte, data interface{}) {}`),
|
func OnNEP11Payment(from interop.Hash160, amount int, token []byte, data interface{}) {}`),
|
||||||
&compiler.Options{Name: "foo"})
|
&compiler.Options{Name: "foo"})
|
||||||
e.DeployContract(t, c, nil)
|
e.DeployContract(t, ctr, nil)
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, to, "transfer",
|
cTo.Invoke(t, true, "transfer", ctr.Hash, []byte("neo.com"), nil)
|
||||||
true, c.Hash.BytesBE(), []byte("neo.com"), nil)
|
cFrom.Invoke(t, 1, "totalSupply")
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, from, "totalSupply", 1)
|
cFrom.Invoke(t, ctr.Hash.BytesBE(), "ownerOf", []byte("neo.com"))
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, from, "ownerOf",
|
|
||||||
c.Hash.BytesBE(), []byte("neo.com"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTokensOf(t *testing.T) {
|
func TestTokensOf(t *testing.T) {
|
||||||
e, nsHash := newExecutorWithNS(t)
|
c := newNSClient(t)
|
||||||
|
e := c.Executor
|
||||||
|
|
||||||
acc1 := e.NewAccount(t)
|
acc1 := e.NewAccount(t)
|
||||||
|
cAcc1 := c.WithSigner(acc1)
|
||||||
acc2 := e.NewAccount(t)
|
acc2 := e.NewAccount(t)
|
||||||
|
cAcc2 := c.WithSigner(acc2)
|
||||||
|
|
||||||
testNameServiceInvoke(t, e, nsHash, "addRoot", stackitem.Null{}, "com")
|
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, acc1, "register",
|
cAcc1.Invoke(t, true, "register", "neo.com", acc1.PrivateKey().GetScriptHash())
|
||||||
true, "neo.com", acc1.PrivateKey().GetScriptHash())
|
cAcc2.Invoke(t, true, "register", "nspcc.com", acc2.PrivateKey().GetScriptHash())
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, acc2, "register",
|
|
||||||
true, "nspcc.com", acc2.PrivateKey().GetScriptHash())
|
|
||||||
|
|
||||||
testTokensOf(t, e, nsHash, [][]byte{[]byte("neo.com")}, acc1.Contract.ScriptHash().BytesBE())
|
testTokensOf(t, c, [][]byte{[]byte("neo.com")}, acc1.Contract.ScriptHash().BytesBE())
|
||||||
testTokensOf(t, e, nsHash, [][]byte{[]byte("nspcc.com")}, acc2.Contract.ScriptHash().BytesBE())
|
testTokensOf(t, c, [][]byte{[]byte("nspcc.com")}, acc2.Contract.ScriptHash().BytesBE())
|
||||||
testTokensOf(t, e, nsHash, [][]byte{[]byte("neo.com"), []byte("nspcc.com")})
|
testTokensOf(t, c, [][]byte{[]byte("neo.com"), []byte("nspcc.com")})
|
||||||
testTokensOf(t, e, nsHash, [][]byte{}, util.Uint160{}.BytesBE()) // empty hash is a valid hash still
|
testTokensOf(t, c, [][]byte{}, util.Uint160{}.BytesBE()) // empty hash is a valid hash still
|
||||||
}
|
}
|
||||||
|
|
||||||
func testTokensOf(t *testing.T, e *neotest.Executor, nsHash util.Uint160, result [][]byte, args ...interface{}) {
|
func testTokensOf(t *testing.T, c *neotest.ContractInvoker, result [][]byte, args ...interface{}) {
|
||||||
method := "tokensOf"
|
method := "tokensOf"
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
method = "tokens"
|
method = "tokens"
|
||||||
}
|
}
|
||||||
w := io.NewBufBinWriter()
|
s, err := c.TestInvoke(t, method, args...)
|
||||||
emit.AppCall(w.BinWriter, nsHash, method, callflag.All, args...)
|
|
||||||
for range result {
|
|
||||||
emit.Opcodes(w.BinWriter, opcode.DUP)
|
|
||||||
emit.Syscall(w.BinWriter, interopnames.SystemIteratorNext)
|
|
||||||
emit.Opcodes(w.BinWriter, opcode.ASSERT)
|
|
||||||
|
|
||||||
emit.Opcodes(w.BinWriter, opcode.DUP)
|
|
||||||
emit.Syscall(w.BinWriter, interopnames.SystemIteratorValue)
|
|
||||||
emit.Opcodes(w.BinWriter, opcode.SWAP)
|
|
||||||
}
|
|
||||||
emit.Opcodes(w.BinWriter, opcode.DROP)
|
|
||||||
emit.Int(w.BinWriter, int64(len(result)))
|
|
||||||
emit.Opcodes(w.BinWriter, opcode.PACK)
|
|
||||||
require.NoError(t, w.Err)
|
|
||||||
script := w.Bytes()
|
|
||||||
tx := transaction.New(script, defaultNameServiceSysfee)
|
|
||||||
tx.ValidUntilBlock = e.Chain.BlockHeight() + 1
|
|
||||||
v, err := neotest.TestInvoke(e.Chain, tx)
|
|
||||||
if result == nil {
|
if result == nil {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
iter := s.Pop().Interop().Value().(*storage.Iterator)
|
||||||
arr := make([]stackitem.Item, 0, len(result))
|
arr := make([]stackitem.Item, 0, len(result))
|
||||||
for i := len(result) - 1; i >= 0; i-- {
|
for i := range result {
|
||||||
|
require.True(t, iter.Next())
|
||||||
|
require.Equal(t, result[i], iter.Value().Value())
|
||||||
arr = append(arr, stackitem.Make(result[i]))
|
arr = append(arr, stackitem.Make(result[i]))
|
||||||
}
|
}
|
||||||
require.Equal(t, stackitem.NewArray(arr), v.Estack().Pop().Item())
|
require.False(t, iter.Next())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResolve(t *testing.T) {
|
func TestResolve(t *testing.T) {
|
||||||
e, nsHash := newExecutorWithNS(t)
|
c := newNSClient(t)
|
||||||
|
e := c.Executor
|
||||||
|
|
||||||
acc := e.NewAccount(t)
|
acc := e.NewAccount(t)
|
||||||
|
cAcc := c.WithSigner(acc)
|
||||||
|
|
||||||
testNameServiceInvoke(t, e, nsHash, "addRoot", stackitem.Null{}, "com")
|
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, acc, "register",
|
cAcc.Invoke(t, true, "register", "neo.com", acc.PrivateKey().GetScriptHash())
|
||||||
true, "neo.com", acc.PrivateKey().GetScriptHash())
|
cAcc.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.A), "1.2.3.4")
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, acc, "setRecord", stackitem.Null{},
|
cAcc.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.CNAME), "alias.com")
|
||||||
"neo.com", int64(nns.A), "1.2.3.4")
|
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, acc, "setRecord", stackitem.Null{},
|
|
||||||
"neo.com", int64(nns.CNAME), "alias.com")
|
|
||||||
|
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultRegisterSysfee, acc, "register",
|
cAcc.Invoke(t, true, "register", "alias.com", acc.PrivateKey().GetScriptHash())
|
||||||
true, "alias.com", acc.PrivateKey().GetScriptHash())
|
cAcc.Invoke(t, stackitem.Null{}, "setRecord", "alias.com", int64(nns.TXT), "sometxt")
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, acc, "setRecord", stackitem.Null{},
|
|
||||||
"alias.com", int64(nns.TXT), "sometxt")
|
|
||||||
|
|
||||||
testNameServiceInvoke(t, e, nsHash, "resolve", "1.2.3.4",
|
c.Invoke(t, "1.2.3.4", "resolve", "neo.com", int64(nns.A))
|
||||||
"neo.com", int64(nns.A))
|
c.Invoke(t, "alias.com", "resolve", "neo.com", int64(nns.CNAME))
|
||||||
testNameServiceInvoke(t, e, nsHash, "resolve", "alias.com",
|
c.Invoke(t, "sometxt", "resolve", "neo.com", int64(nns.TXT))
|
||||||
"neo.com", int64(nns.CNAME))
|
c.Invoke(t, stackitem.Null{}, "resolve", "neo.com", int64(nns.AAAA))
|
||||||
testNameServiceInvoke(t, e, nsHash, "resolve", "sometxt",
|
|
||||||
"neo.com", int64(nns.TXT))
|
|
||||||
testNameServiceInvoke(t, e, nsHash, "resolve", stackitem.Null{},
|
|
||||||
"neo.com", int64(nns.AAAA))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultNameServiceDomainPrice = 10_0000_0000
|
defaultNameServiceDomainPrice = 10_0000_0000
|
||||||
defaultNameServiceSysfee = 6000_0000
|
defaultNameServiceSysfee = 6000_0000
|
||||||
defaultRegisterSysfee = 10_0000_0000 + defaultNameServiceDomainPrice
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func testNameServiceInvoke(t *testing.T, e *neotest.Executor, nsHash util.Uint160, method string, result interface{}, args ...interface{}) {
|
|
||||||
testNameServiceInvokeAux(t, e, nsHash, defaultNameServiceSysfee, e.Committee, method, result, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testNameServiceInvokeAux(t *testing.T, e *neotest.Executor, nsHash util.Uint160, sysfee int64, signer interface{}, method string, result interface{}, args ...interface{}) {
|
|
||||||
if sysfee < 0 {
|
|
||||||
sysfee = defaultNameServiceSysfee
|
|
||||||
}
|
|
||||||
tx := e.PrepareInvokeNoSign(t, nsHash, method, args...)
|
|
||||||
e.SignTx(t, tx, sysfee, signer)
|
|
||||||
e.AddBlock(t, tx)
|
|
||||||
if result == nil {
|
|
||||||
e.CheckFault(t, tx.Hash(), "")
|
|
||||||
} else {
|
|
||||||
e.CheckHalt(t, tx.Hash(), stackitem.Make(result))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -238,8 +238,8 @@ func (e *Executor) SignBlock(b *block.Block) *block.Block {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddBlockCheckHalt is a convenient wrapper over AddNewBlock and CheckHalt.
|
// AddBlockCheckHalt is a convenient wrapper over AddBlock and CheckHalt.
|
||||||
func (e *Executor) AddBlockCheckHalt(t *testing.T, bc blockchainer.Blockchainer, txs ...*transaction.Transaction) *block.Block {
|
func (e *Executor) AddBlockCheckHalt(t *testing.T, txs ...*transaction.Transaction) *block.Block {
|
||||||
b := e.AddNewBlock(t, txs...)
|
b := e.AddNewBlock(t, txs...)
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
e.CheckHalt(t, tx.Hash())
|
e.CheckHalt(t, tx.Hash())
|
||||||
|
|
83
pkg/neotest/client.go
Normal file
83
pkg/neotest/client.go
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package neotest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContractInvoker is a client for specific contract.
|
||||||
|
type ContractInvoker struct {
|
||||||
|
*Executor
|
||||||
|
Hash util.Uint160
|
||||||
|
Signer interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitteeInvoker creates new ContractInvoker for contract with hash h.
|
||||||
|
func (e *Executor) CommitteeInvoker(h util.Uint160) *ContractInvoker {
|
||||||
|
return &ContractInvoker{
|
||||||
|
Executor: e,
|
||||||
|
Hash: h,
|
||||||
|
Signer: e.Committee,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestInvoke creates test VM and invokes method with args.
|
||||||
|
func (c *ContractInvoker) TestInvoke(t *testing.T, method string, args ...interface{}) (*vm.Stack, error) {
|
||||||
|
tx := c.PrepareInvokeNoSign(t, method, args...)
|
||||||
|
b := c.NewUnsignedBlock(t, tx)
|
||||||
|
v, f := c.Chain.GetTestVM(trigger.Application, tx, b)
|
||||||
|
t.Cleanup(f)
|
||||||
|
|
||||||
|
v.LoadWithFlags(tx.Script, callflag.All)
|
||||||
|
err := v.Run()
|
||||||
|
return v.Estack(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSigner creates new client with the provided signer.
|
||||||
|
func (c *ContractInvoker) WithSigner(signer interface{}) *ContractInvoker {
|
||||||
|
newC := *c
|
||||||
|
newC.Signer = signer
|
||||||
|
return &newC
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareInvoke creates new invocation transaction.
|
||||||
|
func (c *ContractInvoker) PrepareInvoke(t *testing.T, method string, args ...interface{}) *transaction.Transaction {
|
||||||
|
return c.Executor.NewTx(t, c.Signer, c.Hash, method, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareInvokeNoSign creates new unsigned invocation transaction.
|
||||||
|
func (c *ContractInvoker) PrepareInvokeNoSign(t *testing.T, method string, args ...interface{}) *transaction.Transaction {
|
||||||
|
return c.Executor.NewUnsignedTx(t, c.Hash, method, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke invokes method with args, persists transaction and checks the result.
|
||||||
|
// Returns transaction hash.
|
||||||
|
func (c *ContractInvoker) Invoke(t *testing.T, result interface{}, method string, args ...interface{}) util.Uint256 {
|
||||||
|
tx := c.PrepareInvoke(t, method, args...)
|
||||||
|
c.AddNewBlock(t, tx)
|
||||||
|
c.CheckHalt(t, tx.Hash(), stackitem.Make(result))
|
||||||
|
return tx.Hash()
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvokeWithFeeFail is like InvokeFail but sets custom system fee for the transaction.
|
||||||
|
func (c *ContractInvoker) InvokeWithFeeFail(t *testing.T, message string, sysFee int64, method string, args ...interface{}) util.Uint256 {
|
||||||
|
tx := c.PrepareInvokeNoSign(t, method, args...)
|
||||||
|
c.Executor.SignTx(t, tx, sysFee, c.Signer)
|
||||||
|
c.AddNewBlock(t, tx)
|
||||||
|
c.CheckFault(t, tx.Hash(), message)
|
||||||
|
return tx.Hash()
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvokeFail invokes method with args, persists transaction and checks the error message.
|
||||||
|
// Returns transaction hash.
|
||||||
|
func (c *ContractInvoker) InvokeFail(t *testing.T, message string, method string, args ...interface{}) {
|
||||||
|
tx := c.PrepareInvoke(t, method, args...)
|
||||||
|
c.AddNewBlock(t, tx)
|
||||||
|
c.CheckFault(t, tx.Hash(), message)
|
||||||
|
}
|
Loading…
Reference in a new issue