interop: add Hash160 encoder\decoder helper

Close #2690.
This commit is contained in:
Anna Shaleva 2022-09-16 19:18:47 +03:00
parent f1fbd6ad4b
commit 7e13140b04
6 changed files with 196 additions and 15 deletions

View file

@ -17,13 +17,17 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/encoding/base58"
cinterop "github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/neotest"
"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/smartcontract/manifest"
"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/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
)
@ -116,6 +120,100 @@ func TestFromAddress(t *testing.T) {
})
}
func TestAddressToHash160BuiltinConversion(t *testing.T) {
a := "NQRLhCpAru9BjGsMwk67vdMwmzKMRgsnnN"
h, err := address.StringToUint160(a)
require.NoError(t, err)
t.Run("builtin conversion", func(t *testing.T) {
src := `package foo
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/lib/address"
)
var addr = address.ToHash160("` + a + `")
func Main() interop.Hash160 {
return addr
}`
prog := eval(t, src, h.BytesBE())
// Address BE bytes expected to be present at program, which indicates that address conversion
// was performed at compile-time.
require.True(t, strings.Contains(string(prog), string(h.BytesBE())))
// On the contrary, there should be no address string.
require.False(t, strings.Contains(string(prog), a))
})
t.Run("generate code", func(t *testing.T) {
src := `package foo
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/lib/address"
)
var addr = "` + a + `"
func Main() interop.Hash160 {
return address.ToHash160(addr)
}`
// Error on CALLT (std.Base58CheckDecode - method of StdLib native contract) is expected, which means
// that address.ToHash160 code was honestly generated by the compiler without any optimisations.
prog := evalWithError(t, src, "(CALLT): runtime error: invalid memory address or nil pointer dereference")
// Address BE bytes expected not to be present at program, which indicates that address conversion
// was not performed at compile-time.
require.False(t, strings.Contains(string(prog), string(h.BytesBE())))
// On the contrary, there should be an address string.
require.True(t, strings.Contains(string(prog), a))
})
}
func TestInvokeAddressToFromHash160(t *testing.T) {
a := "NQRLhCpAru9BjGsMwk67vdMwmzKMRgsnnN"
h, err := address.StringToUint160(a)
require.NoError(t, err)
bc, acc := chain.NewSingle(t)
e := neotest.NewExecutor(t, bc, acc, acc)
src := `package foo
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/lib/address"
)
const addr = "` + a + `"
func ToHash160(a string) interop.Hash160 {
return address.ToHash160(a)
}
func ToHash160AtCompileTime() interop.Hash160 {
return address.ToHash160(addr)
}
func FromHash160(hash interop.Hash160) string {
return address.FromHash160(hash)
}`
ctr := neotest.CompileSource(t, e.CommitteeHash, strings.NewReader(src), &compiler.Options{Name: "Helper"})
e.DeployContract(t, ctr, nil)
c := e.CommitteeInvoker(ctr.Hash)
t.Run("ToHash160", func(t *testing.T) {
t.Run("invalid address length", func(t *testing.T) {
c.InvokeFail(t, "invalid address length", "toHash160", base58.CheckEncode(make([]byte, util.Uint160Size+1+1)))
})
t.Run("invalid prefix", func(t *testing.T) {
c.InvokeFail(t, "invalid address prefix", "toHash160", base58.CheckEncode(append([]byte{address.NEO2Prefix}, h.BytesBE()...)))
})
t.Run("good", func(t *testing.T) {
c.Invoke(t, stackitem.NewBuffer(h.BytesBE()), "toHash160", a)
})
})
t.Run("ToHash160Constant", func(t *testing.T) {
t.Run("good", func(t *testing.T) {
c.Invoke(t, stackitem.NewBuffer(h.BytesBE()), "toHash160AtCompileTime")
})
})
t.Run("FromHash160", func(t *testing.T) {
t.Run("good", func(t *testing.T) {
c.Invoke(t, stackitem.NewByteArray([]byte(a)), "fromHash160", h.BytesBE())
})
t.Run("invalid length", func(t *testing.T) {
c.InvokeFail(t, "invalid Hash160 length", "fromHash160", h.BytesBE()[:15])
})
})
}
func TestAbort(t *testing.T) {
src := `package foo
import "github.com/nspcc-dev/neo-go/pkg/interop/util"