manifest/compiler: drop hashes from ABI and debug info

See neo-project/neo-devpack-dotnet#391 and neo-project/neo#2044.
This commit is contained in:
Roman Khimov 2020-11-18 12:43:51 +03:00
parent 34d2eaf00e
commit b92ea2a48a
16 changed files with 57 additions and 115 deletions

View file

@ -11,16 +11,13 @@ import (
"unicode"
"unicode/utf8"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util"
)
// DebugInfo represents smart-contract debug information.
type DebugInfo struct {
MainPkg string `json:"-"`
Hash util.Uint160 `json:"hash"`
Documents []string `json:"documents"`
Methods []MethodDebugInfo `json:"methods"`
Events []EventDebugInfo `json:"events"`
@ -115,7 +112,6 @@ func (c *codegen) saveSequencePoint(n ast.Node) {
func (c *codegen) emitDebugInfo(contract []byte) *DebugInfo {
d := &DebugInfo{
MainPkg: c.mainPkg.Pkg.Name(),
Hash: hash.Hash160(contract),
Events: []EventDebugInfo{},
Documents: c.documents,
}
@ -427,7 +423,7 @@ func (di *DebugInfo) ConvertToManifest(name string, events []manifest.Event, sup
}
}
result := manifest.NewManifest(di.Hash, name)
result := manifest.NewManifest(name)
if supportedStandards != nil {
result.SupportedStandards = supportedStandards
}
@ -435,7 +431,6 @@ func (di *DebugInfo) ConvertToManifest(name string, events []manifest.Event, sup
events = make([]manifest.Event, 0)
}
result.ABI = manifest.ABI{
Hash: di.Hash,
Methods: methods,
Events: events,
}

View file

@ -4,7 +4,6 @@ import (
"testing"
"github.com/nspcc-dev/neo-go/internal/testserdes"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util"
@ -69,10 +68,6 @@ func _deploy(isUpdate bool) {}
d := c.emitDebugInfo(buf)
require.NotNil(t, d)
t.Run("hash", func(t *testing.T) {
require.True(t, hash.Hash160(buf).Equals(d.Hash))
})
t.Run("return types", func(t *testing.T) {
returnTypes := map[string]string{
"MethodInt": "Integer",
@ -155,7 +150,6 @@ func _deploy(isUpdate bool) {}
expected := &manifest.Manifest{
Name: "MyCTR",
ABI: manifest.ABI{
Hash: hash.Hash160(buf),
Methods: []manifest.Method{
{
Name: "_deploy",
@ -262,7 +256,6 @@ func _deploy(isUpdate bool) {}
},
Extra: nil,
}
require.True(t, expected.ABI.Hash.Equals(actual.ABI.Hash))
require.ElementsMatch(t, expected.ABI.Methods, actual.ABI.Methods)
require.Equal(t, expected.ABI.Events, actual.ABI.Events)
require.Equal(t, expected.Groups, actual.Groups)
@ -304,7 +297,6 @@ func TestSequencePoints(t *testing.T) {
func TestDebugInfo_MarshalJSON(t *testing.T) {
d := &DebugInfo{
Hash: util.Uint160{10, 11, 12, 13},
Documents: []string{"/path/to/file"},
Methods: []MethodDebugInfo{
{

View file

@ -23,7 +23,7 @@ func TestCachedDaoContracts(t *testing.T) {
_, err := dao.GetContractState(sh)
require.NotNil(t, err)
m := manifest.NewManifest(hash.Hash160(script), "Test")
m := manifest.NewManifest("Test")
cs := &state.Contract{
ID: 123,

View file

@ -48,7 +48,7 @@ func CreateFromMethod(ic *interop.Context) error {
return errors.New("invalid method name")
}
currCs, err := ic.DAO.GetContractState(ic.VM.GetCurrentScriptHash())
if err == nil && !currCs.Manifest.CanCall(&cs.Manifest, method) {
if err == nil && !currCs.Manifest.CanCall(h, &cs.Manifest, method) {
return errors.New("method call is not allowed")
}
md := cs.Manifest.ABI.GetMethod(method)

View file

@ -114,7 +114,7 @@ func NewContractMD(name string) *ContractMD {
c.Script = w.Bytes()
c.Hash = hash.Hash160(c.Script)
c.Manifest = *manifest.DefaultManifest(c.Hash, name)
c.Manifest = *manifest.DefaultManifest(name)
return c
}

View file

@ -48,7 +48,7 @@ func callExInternal(ic *interop.Context, h []byte, name string, args []stackitem
}
curr, err := ic.DAO.GetContractState(ic.VM.GetCurrentScriptHash())
if err == nil {
if !curr.Manifest.CanCall(&cs.Manifest, name) {
if !curr.Manifest.CanCall(u, &cs.Manifest, name) {
return errors.New("disallowed method call")
}
}

View file

@ -162,7 +162,6 @@ func contractUpdate(ic *interop.Context) error {
Script: script,
Manifest: contract.Manifest,
}
contract.Manifest.ABI.Hash = newHash
if err := ic.DAO.PutContractState(contract); err != nil {
return fmt.Errorf("failed to update script: %w", err)
}

View file

@ -16,7 +16,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage"
"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/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
@ -294,7 +293,7 @@ func createVMAndPushTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interop
func createVMAndContractState(t *testing.T) (*vm.VM, *state.Contract, *interop.Context, *Blockchain) {
script := []byte("testscript")
m := manifest.NewManifest(hash.Hash160(script), "Test")
m := manifest.NewManifest("Test")
contractState := &state.Contract{
Script: script,
Manifest: *m,

View file

@ -418,7 +418,7 @@ func getTestContractState() (*state.Contract, *state.Contract) {
script := w.Bytes()
h := hash.Hash160(script)
m := manifest.NewManifest(h, "TestMain")
m := manifest.NewManifest("TestMain")
m.ABI.Methods = []manifest.Method{
{
Name: "add",
@ -507,7 +507,7 @@ func getTestContractState() (*state.Contract, *state.Contract) {
}
currScript := []byte{byte(opcode.RET)}
m = manifest.NewManifest(hash.Hash160(currScript), "TestAux")
m = manifest.NewManifest("TestAux")
perm := manifest.NewPermission(manifest.PermissionHash, h)
perm.Methods.Add("add")
perm.Methods.Add("drop")
@ -551,7 +551,7 @@ func TestContractCall(t *testing.T) {
require.NoError(t, ic.DAO.PutContractState(currCs))
currScript := currCs.Script
h := cs.Manifest.ABI.Hash
h := hash.Hash160(cs.Script)
addArgs := stackitem.NewArray([]stackitem.Item{stackitem.Make(1), stackitem.Make(2)})
t.Run("Good", func(t *testing.T) {
@ -669,13 +669,6 @@ func TestContractCreate(t *testing.T) {
compareContractStates(t, cs, actual)
})
t.Run("invalid scripthash", func(t *testing.T) {
cs.Script = append(cs.Script, 0x01)
putArgsOnStack()
require.Error(t, contractCreate(ic))
})
t.Run("contract already exists", func(t *testing.T) {
cs.Script = cs.Script[:len(cs.Script)-1]
require.NoError(t, ic.DAO.PutContractState(cs))
@ -758,9 +751,7 @@ func TestContractUpdate(t *testing.T) {
ID: 95,
Script: duplicateScript,
Manifest: manifest.Manifest{
ABI: manifest.ABI{
Hash: hash.Hash160(duplicateScript),
},
ABI: manifest.ABI{},
},
}))
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
@ -792,7 +783,6 @@ func TestContractUpdate(t *testing.T) {
Script: newScript,
Manifest: cs.Manifest,
}
expected.Manifest.ABI.Hash = hash.Hash160(newScript)
_ = expected.ScriptHash()
require.Equal(t, expected, actual)
@ -809,27 +799,10 @@ func TestContractUpdate(t *testing.T) {
require.Error(t, contractUpdate(ic))
})
t.Run("update manifest, bad contract hash", func(t *testing.T) {
require.NoError(t, ic.DAO.PutContractState(cs))
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
manifest := &manifest.Manifest{
ABI: manifest.ABI{
Hash: util.Uint160{4, 5, 6},
},
}
manifestBytes, err := json.Marshal(manifest)
require.NoError(t, err)
putArgsOnStack(stackitem.Null{}, manifestBytes)
require.Error(t, contractUpdate(ic))
})
t.Run("update manifest, positive", func(t *testing.T) {
require.NoError(t, ic.DAO.PutContractState(cs))
manifest := &manifest.Manifest{
ABI: manifest.ABI{
Hash: cs.ScriptHash(),
},
ABI: manifest.ABI{},
}
manifestBytes, err := json.Marshal(manifest)
require.NoError(t, err)
@ -861,9 +834,7 @@ func TestContractUpdate(t *testing.T) {
v.LoadScriptWithHash([]byte{byte(opcode.RET)}, cs.ScriptHash(), smartcontract.All)
newScript := []byte{12, 13, 14}
newManifest := manifest.Manifest{
ABI: manifest.ABI{
Hash: hash.Hash160(newScript),
},
ABI: manifest.ABI{},
}
newManifestBytes, err := json.Marshal(newManifest)
require.NoError(t, err)
@ -880,7 +851,6 @@ func TestContractUpdate(t *testing.T) {
Script: newScript,
Manifest: newManifest,
}
expected.Manifest.ABI.Hash = hash.Hash160(newScript)
_ = expected.ScriptHash()
require.Equal(t, expected, actual)
@ -926,7 +896,6 @@ func TestContractCreateDeploy(t *testing.T) {
Script: append(cs.Script, byte(opcode.RET)),
Manifest: cs.Manifest,
}
newCs.Manifest.ABI.Hash = hash.Hash160(newCs.Script)
putArgs(newCs)
require.NoError(t, contractUpdate(ic))
require.NoError(t, v.Run())
@ -992,7 +961,7 @@ func TestMethodCallback(t *testing.T) {
require.NoError(t, ic.DAO.PutContractState(currCs))
ic.Functions = append(ic.Functions, systemInterops)
rawHash := cs.Manifest.ABI.Hash.BytesBE()
rawHash := hash.Hash160(cs.Script).BytesBE()
t.Run("Invalid", func(t *testing.T) {
runInvalid := func(args ...interface{}) func(t *testing.T) {

View file

@ -50,7 +50,7 @@ func getOracleContractState(h util.Uint160) *state.Contract {
emit.Syscall(w.BinWriter, interopnames.SystemStoragePut)
emit.Opcodes(w.BinWriter, opcode.RET)
m := manifest.NewManifest(h, "TestOracle")
m := manifest.NewManifest("TestOracle")
m.ABI.Methods = []manifest.Method{
{
Name: "requestURL",

View file

@ -14,7 +14,7 @@ func TestEncodeDecodeContractState(t *testing.T) {
script := []byte("testscript")
h := hash.Hash160(script)
m := manifest.NewManifest(h, "Test")
m := manifest.NewManifest("Test")
m.ABI.Methods = []manifest.Method{{
Name: "main",
Parameters: []manifest.Parameter{

View file

@ -19,7 +19,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"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/rpc/request"
@ -327,13 +326,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
}
return c.GetContractStateByHash(hash)
},
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"name":"Test","abi":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`,
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"name":"Test","abi":{"methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`,
result: func(c *Client) interface{} {
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
if err != nil {
panic(err)
}
m := manifest.NewManifest(hash.Hash160(script), "Test")
m := manifest.NewManifest("Test")
cs := &state.Contract{
ID: 0,
Script: script,
@ -348,13 +347,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
invoke: func(c *Client) (interface{}, error) {
return c.GetContractStateByAddressOrName("NWiu5oejTu925aeL9Hc1LX8SvaJhE23h15")
},
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"name":"Test","abi":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`,
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"name":"Test","abi":{"methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`,
result: func(c *Client) interface{} {
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
if err != nil {
panic(err)
}
m := manifest.NewManifest(hash.Hash160(script), "Test")
m := manifest.NewManifest("Test")
cs := &state.Contract{
ID: 0,
Script: script,
@ -369,13 +368,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
invoke: func(c *Client) (interface{}, error) {
return c.GetContractStateByID(0)
},
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"name":"Test","abi":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`,
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"name":"Test","abi":{"methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`,
result: func(c *Client) interface{} {
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
if err != nil {
panic(err)
}
m := manifest.NewManifest(hash.Hash160(script), "Test")
m := manifest.NewManifest("Test")
cs := &state.Contract{
ID: 0,
Script: script,

View file

@ -32,9 +32,8 @@ const (
// ABI represents a contract application binary interface.
type ABI struct {
Hash util.Uint160 `json:"hash"`
Methods []Method `json:"methods"`
Events []Event `json:"events"`
Methods []Method `json:"methods"`
Events []Event `json:"events"`
}
// Manifest represens contract metadata.
@ -57,11 +56,10 @@ type Manifest struct {
}
// NewManifest returns new manifest with necessary fields initialized.
func NewManifest(h util.Uint160, name string) *Manifest {
func NewManifest(name string) *Manifest {
m := &Manifest{
Name: name,
ABI: ABI{
Hash: h,
Methods: []Method{},
Events: []Event{},
},
@ -74,8 +72,8 @@ func NewManifest(h util.Uint160, name string) *Manifest {
}
// DefaultManifest returns default contract manifest.
func DefaultManifest(h util.Uint160, name string) *Manifest {
m := NewManifest(h, name)
func DefaultManifest(name string) *Manifest {
m := NewManifest(name)
m.Permissions = []Permission{*NewPermission(PermissionWildcard)}
return m
}
@ -101,26 +99,22 @@ func (a *ABI) GetEvent(name string) *Event {
}
// CanCall returns true is current contract is allowed to call
// method of another contract.
func (m *Manifest) CanCall(toCall *Manifest, method string) bool {
// method of another contract with specified hash.
func (m *Manifest) CanCall(hash util.Uint160, toCall *Manifest, method string) bool {
// this if is not present in the original code but should probably be here
if toCall.SafeMethods.Contains(method) {
return true
}
for i := range m.Permissions {
if m.Permissions[i].IsAllowed(toCall, method) {
if m.Permissions[i].IsAllowed(hash, toCall, method) {
return true
}
}
return false
}
// IsValid checks whether the given hash is the one specified in manifest and
// verifies it against all the keys in manifest groups.
// IsValid checks whether the hash given is correct wrt manifest's groups.
func (m *Manifest) IsValid(hash util.Uint160) bool {
if m.ABI.Hash != hash {
return false
}
for _, g := range m.Groups {
if !g.IsValid(hash) {
return false

View file

@ -13,40 +13,40 @@ import (
// https://github.com/neo-project/neo/blob/master/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs#L10
func TestManifest_MarshalJSON(t *testing.T) {
t.Run("default", func(t *testing.T) {
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}`
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}`
m := testUnmarshalMarshalManifest(t, s)
require.Equal(t, DefaultManifest(util.Uint160{}, "Test"), m)
require.Equal(t, DefaultManifest("Test"), m)
})
t.Run("permissions", func(t *testing.T) {
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"0x0000000000000000000000000000000000000000","methods":["method1","method2"]}],"trusts":[],"safemethods":[],"extra":null}`
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"0x0000000000000000000000000000000000000000","methods":["method1","method2"]}],"trusts":[],"safemethods":[],"extra":null}`
testUnmarshalMarshalManifest(t, s)
})
t.Run("safe methods", func(t *testing.T) {
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":["balanceOf"],"extra":null}`
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":["balanceOf"],"extra":null}`
testUnmarshalMarshalManifest(t, s)
})
t.Run("trust", func(t *testing.T) {
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":["0x0000000000000000000000000000000000000001"],"safemethods":[],"extra":null}`
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":["0x0000000000000000000000000000000000000001"],"safemethods":[],"extra":null}`
testUnmarshalMarshalManifest(t, s)
})
t.Run("groups", func(t *testing.T) {
s := `{"groups":[{"pubkey":"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c","signature":"QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ=="}],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}`
s := `{"groups":[{"pubkey":"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c","signature":"QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ=="}],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}`
testUnmarshalMarshalManifest(t, s)
})
t.Run("extra", func(t *testing.T) {
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":{"key":"value"}}`
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":{"key":"value"}}`
testUnmarshalMarshalManifest(t, s)
})
}
func testUnmarshalMarshalManifest(t *testing.T, s string) *Manifest {
js := []byte(s)
c := NewManifest(util.Uint160{}, "Test")
c := NewManifest("Test")
require.NoError(t, json.Unmarshal(js, c))
data, err := json.Marshal(c)
@ -58,43 +58,43 @@ func testUnmarshalMarshalManifest(t *testing.T, s string) *Manifest {
func TestManifest_CanCall(t *testing.T) {
t.Run("safe methods", func(t *testing.T) {
man1 := NewManifest(util.Uint160{}, "Test1")
man2 := DefaultManifest(util.Uint160{}, "Test2")
require.False(t, man1.CanCall(man2, "method1"))
man1 := NewManifest("Test1")
man2 := DefaultManifest("Test2")
require.False(t, man1.CanCall(util.Uint160{}, man2, "method1"))
man2.SafeMethods.Add("method1")
require.True(t, man1.CanCall(man2, "method1"))
require.True(t, man1.CanCall(util.Uint160{}, man2, "method1"))
})
t.Run("wildcard permission", func(t *testing.T) {
man1 := DefaultManifest(util.Uint160{}, "Test1")
man2 := DefaultManifest(util.Uint160{}, "Test2")
require.True(t, man1.CanCall(man2, "method1"))
man1 := DefaultManifest("Test1")
man2 := DefaultManifest("Test2")
require.True(t, man1.CanCall(util.Uint160{}, man2, "method1"))
})
}
func TestPermission_IsAllowed(t *testing.T) {
manifest := DefaultManifest(util.Uint160{}, "Test")
manifest := DefaultManifest("Test")
t.Run("wildcard", func(t *testing.T) {
perm := NewPermission(PermissionWildcard)
require.True(t, perm.IsAllowed(manifest, "AAA"))
require.True(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
})
t.Run("hash", func(t *testing.T) {
perm := NewPermission(PermissionHash, util.Uint160{})
require.True(t, perm.IsAllowed(manifest, "AAA"))
require.True(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
t.Run("restrict methods", func(t *testing.T) {
perm.Methods.Restrict()
require.False(t, perm.IsAllowed(manifest, "AAA"))
require.False(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
perm.Methods.Add("AAA")
require.True(t, perm.IsAllowed(manifest, "AAA"))
require.True(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
})
})
t.Run("invalid hash", func(t *testing.T) {
perm := NewPermission(PermissionHash, util.Uint160{1})
require.False(t, perm.IsAllowed(manifest, "AAA"))
require.False(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
})
priv, err := keys.NewPrivateKey()
@ -103,29 +103,25 @@ func TestPermission_IsAllowed(t *testing.T) {
t.Run("group", func(t *testing.T) {
perm := NewPermission(PermissionGroup, priv.PublicKey())
require.True(t, perm.IsAllowed(manifest, "AAA"))
require.True(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
})
t.Run("invalid group", func(t *testing.T) {
priv2, err := keys.NewPrivateKey()
require.NoError(t, err)
perm := NewPermission(PermissionGroup, priv2.PublicKey())
require.False(t, perm.IsAllowed(manifest, "AAA"))
require.False(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
})
}
func TestIsValid(t *testing.T) {
contractHash := util.Uint160{1, 2, 3}
m := NewManifest(contractHash, "Test")
m := NewManifest("Test")
t.Run("valid, no groups", func(t *testing.T) {
require.True(t, m.IsValid(contractHash))
})
t.Run("invalid, no groups", func(t *testing.T) {
require.False(t, m.IsValid(util.Uint160{9, 8, 7}))
})
t.Run("with groups", func(t *testing.T) {
m.Groups = make([]Group, 3)
pks := make([]*keys.PrivateKey, 3)

View file

@ -84,12 +84,12 @@ func (d *PermissionDesc) Group() *keys.PublicKey {
}
// IsAllowed checks if method is allowed to be executed.
func (p *Permission) IsAllowed(m *Manifest, method string) bool {
func (p *Permission) IsAllowed(hash util.Uint160, m *Manifest, method string) bool {
switch p.Contract.Type {
case PermissionWildcard:
return true
case PermissionHash:
if !p.Contract.Hash().Equals(m.ABI.Hash) {
if !p.Contract.Hash().Equals(hash) {
return false
}
case PermissionGroup:

View file

@ -6,7 +6,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/stretchr/testify/require"
)
@ -106,7 +105,7 @@ func TestComplyValid(t *testing.T) {
}
func TestCheck(t *testing.T) {
m := manifest.NewManifest(util.Uint160{}, "Test")
m := manifest.NewManifest("Test")
require.Error(t, Check(m, manifest.NEP17StandardName))
require.NoError(t, Check(nep17, manifest.NEP17StandardName))