From c849176be7e875c76cb623a6a5e112088079bf9a Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Fri, 20 Nov 2020 11:02:58 +0300 Subject: [PATCH 1/6] manifest: include contract Name --- cli/smartcontract/smart_contract.go | 3 +++ cli/smartcontract/smart_contract_test.go | 3 ++- cli/testdata/verify.manifest.json | 2 +- examples/engine/engine.yml | 1 + examples/iterator/iterator.yml | 1 + examples/runtime/runtime.yml | 1 + examples/storage/storage.yml | 1 + examples/timer/timer.yml | 1 + examples/token-sale/token_sale.yml | 1 + examples/token/token.yml | 1 + pkg/compiler/compiler.go | 5 +++- pkg/compiler/debug.go | 4 +-- pkg/compiler/debug_test.go | 3 ++- pkg/compiler/interop_test.go | 2 +- pkg/core/dao/cacheddao_test.go | 2 +- pkg/core/helper_test.go | 2 +- pkg/core/interop/context.go | 2 +- pkg/core/interop_neo_test.go | 2 +- pkg/core/interop_system_test.go | 4 +-- pkg/core/native_contract_test.go | 2 +- pkg/core/native_oracle_test.go | 2 +- pkg/core/state/contract_test.go | 2 +- pkg/rpc/client/rpc_test.go | 16 ++++++------ pkg/smartcontract/manifest/manifest.go | 9 ++++--- pkg/smartcontract/manifest/manifest_test.go | 28 ++++++++++----------- 25 files changed, 59 insertions(+), 41 deletions(-) diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index a311f0993..4b92ca465 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -349,6 +349,7 @@ func initSmartContract(ctx *cli.Context) error { } m := ProjectConfig{ + Name: contractName, SupportedStandards: []string{}, Events: []manifest.Event{ { @@ -404,6 +405,7 @@ func contractCompile(ctx *cli.Context) error { if err != nil { return err } + o.Name = conf.Name o.ContractEvents = conf.Events o.ContractSupportedStandards = conf.SupportedStandards } @@ -631,6 +633,7 @@ func testInvokeScript(ctx *cli.Context) error { // ProjectConfig contains project metadata. type ProjectConfig struct { + Name string SupportedStandards []string Events []manifest.Event } diff --git a/cli/smartcontract/smart_contract_test.go b/cli/smartcontract/smart_contract_test.go index b8c019b73..8264cb858 100644 --- a/cli/smartcontract/smart_contract_test.go +++ b/cli/smartcontract/smart_contract_test.go @@ -58,7 +58,8 @@ func RuntimeNotify(args []interface{}) { manifest, err := ioutil.ReadFile(contractName + "/" + files[1].Name()) require.NoError(t, err) require.Equal(t, - `supportedstandards: [] + `name: testContract +supportedstandards: [] events: - name: Hello world! parameters: diff --git a/cli/testdata/verify.manifest.json b/cli/testdata/verify.manifest.json index 910fce3b8..10f37f908 100755 --- a/cli/testdata/verify.manifest.json +++ b/cli/testdata/verify.manifest.json @@ -1 +1 @@ -{"abi":{"hash":"0x8dff9f223e4622961f410c015dd37052a59892bb","methods":[{"name":"verify","offset":0,"parameters":[],"returntype":"Boolean"}],"events":[]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"safemethods":[],"extra":null} +{"name":"Verify","abi":{"hash":"0x8dff9f223e4622961f410c015dd37052a59892bb","methods":[{"name":"verify","offset":0,"parameters":[],"returntype":"Boolean"}],"events":[]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"safemethods":[],"extra":null} \ No newline at end of file diff --git a/examples/engine/engine.yml b/examples/engine/engine.yml index 2bf0986ef..4b2d24672 100644 --- a/examples/engine/engine.yml +++ b/examples/engine/engine.yml @@ -1,3 +1,4 @@ +name: "Engine example" supportedstandards: [] events: - name: Tx diff --git a/examples/iterator/iterator.yml b/examples/iterator/iterator.yml index b81bef6f6..ab4788d0a 100644 --- a/examples/iterator/iterator.yml +++ b/examples/iterator/iterator.yml @@ -1,3 +1,4 @@ +name: "Iterator example" supportedstandards: [] events: - name: found storage values diff --git a/examples/runtime/runtime.yml b/examples/runtime/runtime.yml index 25adbd20f..c24377b55 100644 --- a/examples/runtime/runtime.yml +++ b/examples/runtime/runtime.yml @@ -1,3 +1,4 @@ +name: "Runtime example" supportedstandards: [] events: - name: Event diff --git a/examples/storage/storage.yml b/examples/storage/storage.yml index d25be3663..9aa294359 100644 --- a/examples/storage/storage.yml +++ b/examples/storage/storage.yml @@ -1,2 +1,3 @@ +name: "Storage example" supportedstandards: [] events: [] diff --git a/examples/timer/timer.yml b/examples/timer/timer.yml index d25be3663..5e6cbed6b 100644 --- a/examples/timer/timer.yml +++ b/examples/timer/timer.yml @@ -1,2 +1,3 @@ +name: "Timer example" supportedstandards: [] events: [] diff --git a/examples/token-sale/token_sale.yml b/examples/token-sale/token_sale.yml index a50d94c56..56f3d4d9b 100644 --- a/examples/token-sale/token_sale.yml +++ b/examples/token-sale/token_sale.yml @@ -1,2 +1,3 @@ +name: "My awesome token" supportedstandards: ["NEP-5"] events: [] diff --git a/examples/token/token.yml b/examples/token/token.yml index 5c565f98e..b6ee7f862 100644 --- a/examples/token/token.yml +++ b/examples/token/token.yml @@ -1,3 +1,4 @@ +name: "Awesome NEO Token" supportedstandards: ["NEP-5"] events: - name: transfer diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index eb81462e3..cc7ce5f7f 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -34,6 +34,9 @@ type Options struct { // The name of the output for contract manifest file. ManifestFile string + // Name is contract's name to be written to manifest. + Name string + // Runtime notifications. ContractEvents []manifest.Event @@ -207,7 +210,7 @@ func CompileAndSave(src string, o *Options) ([]byte, error) { } if o.ManifestFile != "" { - m, err := di.ConvertToManifest(o.ContractEvents, o.ContractSupportedStandards...) + m, err := di.ConvertToManifest(o.Name, o.ContractEvents, o.ContractSupportedStandards...) if err != nil { return b, fmt.Errorf("failed to convert debug info to manifest: %w", err) } diff --git a/pkg/compiler/debug.go b/pkg/compiler/debug.go index 2cf71ff7e..02181a665 100644 --- a/pkg/compiler/debug.go +++ b/pkg/compiler/debug.go @@ -409,7 +409,7 @@ func parsePairJSON(data []byte, sep string) (string, string, error) { // ConvertToManifest converts contract to the manifest.Manifest struct for debugger. // Note: manifest is taken from the external source, however it can be generated ad-hoc. See #1038. -func (di *DebugInfo) ConvertToManifest(events []manifest.Event, supportedStandards ...string) (*manifest.Manifest, error) { +func (di *DebugInfo) ConvertToManifest(name string, events []manifest.Event, supportedStandards ...string) (*manifest.Manifest, error) { if di.MainPkg == "" { return nil, errors.New("no Main method was found") } @@ -424,7 +424,7 @@ func (di *DebugInfo) ConvertToManifest(events []manifest.Event, supportedStandar } } - result := manifest.NewManifest(di.Hash) + result := manifest.NewManifest(di.Hash, name) if supportedStandards != nil { result.SupportedStandards = supportedStandards } diff --git a/pkg/compiler/debug_test.go b/pkg/compiler/debug_test.go index 83d0f0e35..6db467af8 100644 --- a/pkg/compiler/debug_test.go +++ b/pkg/compiler/debug_test.go @@ -149,10 +149,11 @@ func _deploy(isUpdate bool) {} } t.Run("convert to Manifest", func(t *testing.T) { - actual, err := d.ConvertToManifest(nil) + actual, err := d.ConvertToManifest("MyCTR", nil) require.NoError(t, err) // note: offsets are hard to predict, so we just take them from the output expected := &manifest.Manifest{ + Name: "MyCTR", ABI: manifest.ABI{ Hash: hash.Hash160(buf), Methods: []manifest.Method{ diff --git a/pkg/compiler/interop_test.go b/pkg/compiler/interop_test.go index c484f5db4..7150bfb01 100644 --- a/pkg/compiler/interop_test.go +++ b/pkg/compiler/interop_test.go @@ -101,7 +101,7 @@ func TestAppCall(t *testing.T) { inner, di, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(srcInner)) require.NoError(t, err) - m, err := di.ConvertToManifest(nil) + m, err := di.ConvertToManifest("Foo", nil) require.NoError(t, err) ih := hash.Hash160(inner) diff --git a/pkg/core/dao/cacheddao_test.go b/pkg/core/dao/cacheddao_test.go index 6a58debaa..8263aa707 100644 --- a/pkg/core/dao/cacheddao_test.go +++ b/pkg/core/dao/cacheddao_test.go @@ -23,7 +23,7 @@ func TestCachedDaoContracts(t *testing.T) { _, err := dao.GetContractState(sh) require.NotNil(t, err) - m := manifest.NewManifest(hash.Hash160(script)) + m := manifest.NewManifest(hash.Hash160(script), "Test") cs := &state.Contract{ ID: 123, diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index 63119ab2e..4fd78e494 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -398,7 +398,7 @@ func newDeployTx(t *testing.T, name string) (*transaction.Transaction, []byte) { t.Logf("contractScript: %x", avm) script := io.NewBufBinWriter() - m, err := di.ConvertToManifest(nil) + m, err := di.ConvertToManifest("Test", nil) require.NoError(t, err) bs, err := json.Marshal(m) require.NoError(t, err) diff --git a/pkg/core/interop/context.go b/pkg/core/interop/context.go index 7528f61f6..df4075889 100644 --- a/pkg/core/interop/context.go +++ b/pkg/core/interop/context.go @@ -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) + c.Manifest = *manifest.DefaultManifest(c.Hash, name) return c } diff --git a/pkg/core/interop_neo_test.go b/pkg/core/interop_neo_test.go index 47b6c34b8..e17ae875a 100644 --- a/pkg/core/interop_neo_test.go +++ b/pkg/core/interop_neo_test.go @@ -294,7 +294,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)) + m := manifest.NewManifest(hash.Hash160(script), "Test") contractState := &state.Contract{ Script: script, Manifest: *m, diff --git a/pkg/core/interop_system_test.go b/pkg/core/interop_system_test.go index 8f60fc075..83cee6892 100644 --- a/pkg/core/interop_system_test.go +++ b/pkg/core/interop_system_test.go @@ -411,7 +411,7 @@ func getTestContractState() (*state.Contract, *state.Contract) { script := w.Bytes() h := hash.Hash160(script) - m := manifest.NewManifest(h) + m := manifest.NewManifest(h, "TestMain") m.ABI.Methods = []manifest.Method{ { Name: "add", @@ -490,7 +490,7 @@ func getTestContractState() (*state.Contract, *state.Contract) { } currScript := []byte{byte(opcode.RET)} - m = manifest.NewManifest(hash.Hash160(currScript)) + m = manifest.NewManifest(hash.Hash160(currScript), "TestAux") perm := manifest.NewPermission(manifest.PermissionHash, h) perm.Methods.Add("add") perm.Methods.Add("drop") diff --git a/pkg/core/native_contract_test.go b/pkg/core/native_contract_test.go index 3a438c365..b1d0dee3f 100644 --- a/pkg/core/native_contract_test.go +++ b/pkg/core/native_contract_test.go @@ -325,7 +325,7 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) { // put some other contract into chain (this contract just pushes `5` on stack) avm := []byte{byte(opcode.PUSH5), byte(opcode.RET)} contractHash := hash.Hash160(avm) - m := manifest.NewManifest(contractHash) + m := manifest.NewManifest(contractHash, "Test") m.ABI.Methods = []manifest.Method{ { Name: "five", diff --git a/pkg/core/native_oracle_test.go b/pkg/core/native_oracle_test.go index 3df0c9b55..8e091a28b 100644 --- a/pkg/core/native_oracle_test.go +++ b/pkg/core/native_oracle_test.go @@ -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) + m := manifest.NewManifest(h, "TestOracle") m.ABI.Methods = []manifest.Method{ { Name: "requestURL", diff --git a/pkg/core/state/contract_test.go b/pkg/core/state/contract_test.go index cc2936fea..95b8ccb52 100644 --- a/pkg/core/state/contract_test.go +++ b/pkg/core/state/contract_test.go @@ -14,7 +14,7 @@ func TestEncodeDecodeContractState(t *testing.T) { script := []byte("testscript") h := hash.Hash160(script) - m := manifest.NewManifest(h) + m := manifest.NewManifest(h, "Test") m.ABI.Methods = []manifest.Method{{ Name: "main", Parameters: []manifest.Parameter{ diff --git a/pkg/rpc/client/rpc_test.go b/pkg/rpc/client/rpc_test.go index b82f3f74c..0fa8727a0 100644 --- a/pkg/rpc/client/rpc_test.go +++ b/pkg/rpc/client/rpc_test.go @@ -327,13 +327,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ } return c.GetContractStateByHash(hash) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"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":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","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)) + m := manifest.NewManifest(hash.Hash160(script), "Test") cs := &state.Contract{ ID: 0, Script: script, @@ -348,13 +348,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":{"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":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","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)) + m := manifest.NewManifest(hash.Hash160(script), "Test") cs := &state.Contract{ ID: 0, Script: script, @@ -369,13 +369,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":{"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":{"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","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)) + m := manifest.NewManifest(hash.Hash160(script), "Test") cs := &state.Contract{ ID: 0, Script: script, @@ -1463,9 +1463,9 @@ func wrapInitResponse(r *request.In, resp string) string { } switch name { case "neo": - response = `{"id":1,"jsonrpc":"2.0","result":{"id":-1,"script":"DANORU9Ba2d4Cw==","manifest":{"abi":{"hash":"0xde5f57d430d3dece511cf975a8d37848cb9e0525","methods":[{"name":"name","offset":0,"parameters":null,"returntype":"String"},{"name":"symbol","offset":0,"parameters":null,"returntype":"String"},{"name":"decimals","offset":0,"parameters":null,"returntype":"Integer"},{"name":"totalSupply","offset":0,"parameters":null,"returntype":"Integer"},{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer"},{"name":"transfer","offset":0,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Boolean"},{"name":"onPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"postPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"unclaimedGas","offset":0,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer"},{"name":"registerCandidate","offset":0,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"unregisterCandidate","offset":0,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"vote","offset":0,"parameters":[{"name":"account","type":"Hash160"},{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"getCandidates","offset":0,"parameters":null,"returntype":"Array"},{"name":"getСommittee","offset":0,"parameters":null,"returntype":"Array"},{"name":"getNextBlockValidators","offset":0,"parameters":null,"returntype":"Array"},{"name":"getGasPerBlock","offset":0,"parameters":null,"returntype":"Integer"},{"name":"setGasPerBlock","offset":0,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Boolean"}],"events":[{"name":"Transfer","parameters":null}]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-5"],"trusts":[],"safemethods":["name","symbol","decimals","totalSupply","balanceOf","unclaimedGas","getCandidates","getСommittee","getNextBlockValidators"],"extra":null},"hash":"0xde5f57d430d3dece511cf975a8d37848cb9e0525"}}` + response = `{"id":1,"jsonrpc":"2.0","result":{"id":-1,"script":"DANORU9Ba2d4Cw==","manifest":{"name":"NEO","abi":{"hash":"0xde5f57d430d3dece511cf975a8d37848cb9e0525","methods":[{"name":"name","offset":0,"parameters":null,"returntype":"String"},{"name":"symbol","offset":0,"parameters":null,"returntype":"String"},{"name":"decimals","offset":0,"parameters":null,"returntype":"Integer"},{"name":"totalSupply","offset":0,"parameters":null,"returntype":"Integer"},{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer"},{"name":"transfer","offset":0,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Boolean"},{"name":"onPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"postPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"unclaimedGas","offset":0,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer"},{"name":"registerCandidate","offset":0,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"unregisterCandidate","offset":0,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"vote","offset":0,"parameters":[{"name":"account","type":"Hash160"},{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean"},{"name":"getCandidates","offset":0,"parameters":null,"returntype":"Array"},{"name":"getСommittee","offset":0,"parameters":null,"returntype":"Array"},{"name":"getNextBlockValidators","offset":0,"parameters":null,"returntype":"Array"},{"name":"getGasPerBlock","offset":0,"parameters":null,"returntype":"Integer"},{"name":"setGasPerBlock","offset":0,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Boolean"}],"events":[{"name":"Transfer","parameters":null}]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-5"],"trusts":[],"safemethods":["name","symbol","decimals","totalSupply","balanceOf","unclaimedGas","getCandidates","getСommittee","getNextBlockValidators"],"extra":null},"hash":"0xde5f57d430d3dece511cf975a8d37848cb9e0525"}}` case "gas": - response = `{"id":1,"jsonrpc":"2.0","result":{"id":-2,"script":"DANHQVNBa2d4Cw==","manifest":{"abi":{"hash":"0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc","methods":[{"name":"name","offset":0,"parameters":null,"returntype":"String"},{"name":"symbol","offset":0,"parameters":null,"returntype":"String"},{"name":"decimals","offset":0,"parameters":null,"returntype":"Integer"},{"name":"totalSupply","offset":0,"parameters":null,"returntype":"Integer"},{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer"},{"name":"transfer","offset":0,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Boolean"},{"name":"onPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"postPersist","offset":0,"parameters":null,"returntype":"Void"}],"events":[{"name":"Transfer","parameters":null}]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-5"],"trusts":[],"safemethods":["name","symbol","decimals","totalSupply","balanceOf"],"extra":null},"hash":"0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"}}` + response = `{"id":1,"jsonrpc":"2.0","result":{"id":-2,"script":"DANHQVNBa2d4Cw==","manifest":{"name":"GAS","abi":{"hash":"0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc","methods":[{"name":"name","offset":0,"parameters":null,"returntype":"String"},{"name":"symbol","offset":0,"parameters":null,"returntype":"String"},{"name":"decimals","offset":0,"parameters":null,"returntype":"Integer"},{"name":"totalSupply","offset":0,"parameters":null,"returntype":"Integer"},{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer"},{"name":"transfer","offset":0,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Boolean"},{"name":"onPersist","offset":0,"parameters":null,"returntype":"Void"},{"name":"postPersist","offset":0,"parameters":null,"returntype":"Void"}],"events":[{"name":"Transfer","parameters":null}]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-5"],"trusts":[],"safemethods":["name","symbol","decimals","totalSupply","balanceOf"],"extra":null},"hash":"0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"}}` default: response = resp } diff --git a/pkg/smartcontract/manifest/manifest.go b/pkg/smartcontract/manifest/manifest.go index 9c3b56fad..fa72ea16b 100644 --- a/pkg/smartcontract/manifest/manifest.go +++ b/pkg/smartcontract/manifest/manifest.go @@ -35,6 +35,8 @@ type ABI struct { // Manifest represens contract metadata. type Manifest struct { + // Name is a contract's name. + Name string `json:"name"` // ABI is a contract's ABI. ABI ABI `json:"abi"` // Groups is a set of groups to which a contract belongs. @@ -51,8 +53,9 @@ type Manifest struct { } // NewManifest returns new manifest with necessary fields initialized. -func NewManifest(h util.Uint160) *Manifest { +func NewManifest(h util.Uint160, name string) *Manifest { m := &Manifest{ + Name: name, ABI: ABI{ Hash: h, Methods: []Method{}, @@ -67,8 +70,8 @@ func NewManifest(h util.Uint160) *Manifest { } // DefaultManifest returns default contract manifest. -func DefaultManifest(h util.Uint160) *Manifest { - m := NewManifest(h) +func DefaultManifest(h util.Uint160, name string) *Manifest { + m := NewManifest(h, name) m.Permissions = []Permission{*NewPermission(PermissionWildcard)} return m } diff --git a/pkg/smartcontract/manifest/manifest_test.go b/pkg/smartcontract/manifest/manifest_test.go index cb48c1edb..2c310dc26 100644 --- a/pkg/smartcontract/manifest/manifest_test.go +++ b/pkg/smartcontract/manifest/manifest_test.go @@ -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":[],"abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}` + s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}` m := testUnmarshalMarshalManifest(t, s) - require.Equal(t, DefaultManifest(util.Uint160{}), m) + require.Equal(t, DefaultManifest(util.Uint160{}, "Test"), m) }) t.Run("permissions", func(t *testing.T) { - s := `{"groups":[],"supportedstandards":[],"abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"0x0000000000000000000000000000000000000000","methods":["method1","method2"]}],"trusts":[],"safemethods":[],"extra":null}` + s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","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":[],"abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":["balanceOf"],"extra":null}` + s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":["balanceOf"],"extra":null}` testUnmarshalMarshalManifest(t, s) }) t.Run("trust", func(t *testing.T) { - s := `{"groups":[],"supportedstandards":[],"abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":["0x0000000000000000000000000000000000000001"],"safemethods":[],"extra":null}` + s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","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":[],"abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}` + s := `{"groups":[{"pubkey":"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c","signature":"QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ=="}],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}` testUnmarshalMarshalManifest(t, s) }) t.Run("extra", func(t *testing.T) { - s := `{"groups":[],"supportedstandards":[],"abi":{"hash":"0x0000000000000000000000000000000000000000","methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":{"key":"value"}}` + s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"hash":"0x0000000000000000000000000000000000000000","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{}) + c := NewManifest(util.Uint160{}, "Test") require.NoError(t, json.Unmarshal(js, c)) data, err := json.Marshal(c) @@ -58,22 +58,22 @@ 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{}) - man2 := DefaultManifest(util.Uint160{}) + man1 := NewManifest(util.Uint160{}, "Test1") + man2 := DefaultManifest(util.Uint160{}, "Test2") require.False(t, man1.CanCall(man2, "method1")) man2.SafeMethods.Add("method1") require.True(t, man1.CanCall(man2, "method1")) }) t.Run("wildcard permission", func(t *testing.T) { - man1 := DefaultManifest(util.Uint160{}) - man2 := DefaultManifest(util.Uint160{}) + man1 := DefaultManifest(util.Uint160{}, "Test1") + man2 := DefaultManifest(util.Uint160{}, "Test2") require.True(t, man1.CanCall(man2, "method1")) }) } func TestPermission_IsAllowed(t *testing.T) { - manifest := DefaultManifest(util.Uint160{}) + manifest := DefaultManifest(util.Uint160{}, "Test") t.Run("wildcard", func(t *testing.T) { perm := NewPermission(PermissionWildcard) @@ -116,7 +116,7 @@ func TestPermission_IsAllowed(t *testing.T) { func TestIsValid(t *testing.T) { contractHash := util.Uint160{1, 2, 3} - m := NewManifest(contractHash) + m := NewManifest(contractHash, "Test") t.Run("valid, no groups", func(t *testing.T) { require.True(t, m.IsValid(contractHash)) From 4de233b3396c7335969136814093df9f6efc293f Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 24 Nov 2020 11:08:52 +0300 Subject: [PATCH 2/6] emit: allow to emit nested arrays --- pkg/vm/emit/emit.go | 2 ++ pkg/vm/emit/emit_test.go | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/vm/emit/emit.go b/pkg/vm/emit/emit.go index a4825e82f..37d6bd7c7 100644 --- a/pkg/vm/emit/emit.go +++ b/pkg/vm/emit/emit.go @@ -70,6 +70,8 @@ func Int(w *io.BinWriter, i int64) { func Array(w *io.BinWriter, es ...interface{}) { for i := len(es) - 1; i >= 0; i-- { switch e := es[i].(type) { + case []interface{}: + Array(w, e...) case int64: Int(w, e) case string: diff --git a/pkg/vm/emit/emit_test.go b/pkg/vm/emit/emit_test.go index 5133d7ca6..be2aad6d0 100644 --- a/pkg/vm/emit/emit_test.go +++ b/pkg/vm/emit/emit_test.go @@ -143,7 +143,7 @@ func TestBytes(t *testing.T) { func TestEmitArray(t *testing.T) { t.Run("good", func(t *testing.T) { buf := io.NewBufBinWriter() - Array(buf.BinWriter, nil, int64(1), "str", true, []byte{0xCA, 0xFE}) + Array(buf.BinWriter, []interface{}{int64(1), int64(2)}, nil, int64(1), "str", true, []byte{0xCA, 0xFE}) require.NoError(t, buf.Err) res := buf.Bytes() @@ -156,6 +156,10 @@ func TestEmitArray(t *testing.T) { assert.EqualValues(t, []byte("str"), res[7:10]) assert.EqualValues(t, opcode.PUSH1, res[10]) assert.EqualValues(t, opcode.PUSHNULL, res[11]) + assert.EqualValues(t, opcode.PUSH2, res[12]) + assert.EqualValues(t, opcode.PUSH1, res[13]) + assert.EqualValues(t, opcode.PUSH2, res[14]) + assert.EqualValues(t, opcode.PACK, res[15]) }) t.Run("empty", func(t *testing.T) { From 42ae226f9e03be182554d1110380a0f9965b4526 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 19 Nov 2020 18:02:21 +0300 Subject: [PATCH 3/6] native: use proper stack for result When native method calls other contract result should be put on the stack of current context. With oracles this problem wasn't noticed because of void return type. --- pkg/core/interop_system_test.go | 2 +- pkg/core/native/interop.go | 3 +- pkg/core/native_contract_test.go | 151 +++++++------------------------ pkg/vm/context.go | 5 + 4 files changed, 40 insertions(+), 121 deletions(-) diff --git a/pkg/core/interop_system_test.go b/pkg/core/interop_system_test.go index 83cee6892..a382afbda 100644 --- a/pkg/core/interop_system_test.go +++ b/pkg/core/interop_system_test.go @@ -454,7 +454,7 @@ func getTestContractState() (*state.Contract, *state.Contract) { { Name: "justReturn", Offset: justRetOff, - ReturnType: smartcontract.IntegerType, + ReturnType: smartcontract.VoidType, }, { Name: manifest.MethodVerify, diff --git a/pkg/core/native/interop.go b/pkg/core/native/interop.go index 05ee8afcb..fef3ecbc4 100644 --- a/pkg/core/native/interop.go +++ b/pkg/core/native/interop.go @@ -62,9 +62,10 @@ func Call(ic *interop.Context) error { if !ic.VM.AddGas(m.Price) { return errors.New("gas limit exceeded") } + ctx := ic.VM.Context() result := m.Func(ic, args) if m.MD.ReturnType != smartcontract.VoidType { - ic.VM.Estack().PushVal(result) + ctx.Estack().PushVal(result) } return nil } diff --git a/pkg/core/native_contract_test.go b/pkg/core/native_contract_test.go index b1d0dee3f..02dffe1d1 100644 --- a/pkg/core/native_contract_test.go +++ b/pkg/core/native_contract_test.go @@ -12,7 +12,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/io" "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" @@ -20,7 +19,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm" "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/stretchr/testify/require" ) @@ -80,30 +78,16 @@ func newTestNative() *testNative { tn.meta.AddMethod(md, desc, true) desc = &manifest.Method{ - Name: "callOtherContractWithoutArgs", - Parameters: []manifest.Parameter{ - manifest.NewParameter("contractHash", smartcontract.Hash160Type), - manifest.NewParameter("method", smartcontract.StringType), - }, - ReturnType: smartcontract.AnyType, - } - md = &interop.MethodAndPrice{ - Func: tn.callOtherContractWithoutArgs, - Price: testSumPrice, - RequiredFlags: smartcontract.NoneFlag} - tn.meta.AddMethod(md, desc, true) - - desc = &manifest.Method{ - Name: "callOtherContractWithArg", + Name: "callOtherContractNoReturn", Parameters: []manifest.Parameter{ manifest.NewParameter("contractHash", smartcontract.Hash160Type), manifest.NewParameter("method", smartcontract.StringType), manifest.NewParameter("arg", smartcontract.ArrayType), }, - ReturnType: smartcontract.AnyType, + ReturnType: smartcontract.VoidType, } md = &interop.MethodAndPrice{ - Func: tn.callOtherContractWithArg, + Func: tn.callOtherContractNoReturn, Price: testSumPrice, RequiredFlags: smartcontract.NoneFlag} tn.meta.AddMethod(md, desc, true) @@ -127,36 +111,36 @@ func (tn *testNative) sum(_ *interop.Context, args []stackitem.Item) stackitem.I return stackitem.NewBigInteger(s1.Add(s1, s2)) } -func (tn *testNative) callOtherContractWithoutArgs(ic *interop.Context, args []stackitem.Item) stackitem.Item { - vm := ic.VM - vm.Estack().PushVal(stackitem.NewArray([]stackitem.Item{})) // no args - vm.Estack().PushVal(args[1]) // method - vm.Estack().PushVal(args[0]) // contract hash - err := contract.Call(ic) +func toUint160(item stackitem.Item) util.Uint160 { + bs, err := item.TryBytes() if err != nil { - return stackitem.NewBigInteger(big.NewInt(-1)) + panic(err) } - _ = vm.Run() - if vm.HasFailed() { - return stackitem.NewBigInteger(big.NewInt(-2)) + u, err := util.Uint160DecodeBytesBE(bs) + if err != nil { + panic(err) } - return vm.Estack().Pop().Item() + return u } -func (tn *testNative) callOtherContractWithArg(ic *interop.Context, args []stackitem.Item) stackitem.Item { - vm := ic.VM - vm.Estack().PushVal(stackitem.NewArray([]stackitem.Item{args[2]})) // arg - vm.Estack().PushVal(args[1]) // method - vm.Estack().PushVal(args[0]) // contract hash - err := contract.Call(ic) +func (tn *testNative) call(ic *interop.Context, args []stackitem.Item, retState vm.CheckReturnState) { + cs, err := ic.DAO.GetContractState(toUint160(args[0])) if err != nil { - return stackitem.NewBigInteger(big.NewInt(-1)) + panic(err) } - _ = vm.Run() - if vm.HasFailed() { - return stackitem.NewBigInteger(big.NewInt(-2)) + bs, err := args[1].TryBytes() + if err != nil { + panic(err) } - return vm.Estack().Pop().Item() + err = contract.CallExInternal(ic, cs, string(bs), args[2].Value().([]stackitem.Item), smartcontract.All, retState) + if err != nil { + panic(err) + } +} + +func (tn *testNative) callOtherContractNoReturn(ic *interop.Context, args []stackitem.Item) stackitem.Item { + tn.call(ic, args, vm.EnsureIsEmpty) + return stackitem.Null{} } func TestNativeContract_Invoke(t *testing.T) { @@ -265,84 +249,13 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) { }) require.NoError(t, err) - t.Run("native Policy, getFeePerByte", func(t *testing.T) { + cs, _ := getTestContractState() + require.NoError(t, chain.dao.PutContractState(cs)) + + t.Run("non-native, no return", func(t *testing.T) { w := io.NewBufBinWriter() - emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "callOtherContractWithoutArgs", chain.contracts.Policy.Hash, "getFeePerByte") - require.NoError(t, w.Err) - script := w.Bytes() - tx := transaction.New(chain.GetConfig().Magic, script, testSumPrice*4+10000) - validUntil := chain.blockHeight + 1 - tx.ValidUntilBlock = validUntil - addSigners(tx) - require.NoError(t, signTx(chain, tx)) - - b := chain.newBlock(tx) - require.NoError(t, chain.AddBlock(b)) - - res, err := chain.GetAppExecResults(tx.Hash(), trigger.Application) - require.NoError(t, err) - require.Equal(t, 1, len(res)) - // we expect it to be FeePerByte from Policy contract - require.Equal(t, vm.HaltState, res[0].VMState) - require.Equal(t, 1, len(res[0].Stack)) - require.Equal(t, big.NewInt(1000), res[0].Stack[0].Value()) - }) - - t.Run("native Policy, setFeePerByte", func(t *testing.T) { - w := io.NewBufBinWriter() - emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "callOtherContractWithArg", chain.contracts.Policy.Hash, "setFeePerByte", int64(500)) - require.NoError(t, w.Err) - script := w.Bytes() - tx := transaction.New(chain.GetConfig().Magic, script, testSumPrice*5+18000) - validUntil := chain.blockHeight + 1 - tx.ValidUntilBlock = validUntil - addSigners(tx) - // to pass policy.checkValidators - tx.Signers[0].Scopes = transaction.Global - require.NoError(t, signTx(chain, tx)) - - b := chain.newBlock(tx) - require.NoError(t, chain.AddBlock(b)) - - require.NoError(t, chain.persist()) - - res, err := chain.GetAppExecResults(tx.Hash(), trigger.Application) - require.NoError(t, err) - require.Equal(t, 1, len(res)) - // we expect it to be `true` which means that native policy value was successfully updated - require.Equal(t, vm.HaltState, res[0].VMState) - require.Equal(t, 1, len(res[0].Stack)) - require.Equal(t, true, res[0].Stack[0].Value()) - - require.NoError(t, chain.persist()) - - // check that feePerByte was updated - n := chain.contracts.Policy.GetFeePerByteInternal(chain.dao) - require.Equal(t, 500, int(n)) - }) - - t.Run("non-native contract", func(t *testing.T) { - // put some other contract into chain (this contract just pushes `5` on stack) - avm := []byte{byte(opcode.PUSH5), byte(opcode.RET)} - contractHash := hash.Hash160(avm) - m := manifest.NewManifest(contractHash, "Test") - m.ABI.Methods = []manifest.Method{ - { - Name: "five", - Offset: 0, - Parameters: []manifest.Parameter{}, - ReturnType: smartcontract.IntegerType, - }, - } - - err = chain.dao.PutContractState(&state.Contract{ - Script: avm, - Manifest: *m, - }) - require.NoError(t, err) - - w := io.NewBufBinWriter() - emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "callOtherContractWithoutArgs", contractHash, "five") + emit.AppCallWithOperationAndArgs(w.BinWriter, tn.Metadata().Hash, "callOtherContractNoReturn", + cs.ScriptHash(), "justReturn", []interface{}{}) require.NoError(t, w.Err) script := w.Bytes() tx := transaction.New(chain.GetConfig().Magic, script, testSumPrice*4+10000) @@ -359,7 +272,7 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) { require.Equal(t, 1, len(res)) require.Equal(t, vm.HaltState, res[0].VMState) require.Equal(t, 1, len(res[0].Stack)) - require.Equal(t, int64(5), res[0].Stack[0].Value().(*big.Int).Int64()) + require.Equal(t, stackitem.Null{}, res[0].Stack[0]) // simple call is done with EnsureNotEmpty }) } diff --git a/pkg/vm/context.go b/pkg/vm/context.go index 10da72c0a..4017f7516 100644 --- a/pkg/vm/context.go +++ b/pkg/vm/context.go @@ -72,6 +72,11 @@ func NewContext(b []byte) *Context { } } +// Estack returns the evaluation stack of c. +func (c *Context) Estack() *Stack { + return c.estack +} + // NextIP returns next instruction pointer. func (c *Context) NextIP() int { return c.nextip From a5914f89fa62c240a1d0ea454892899097df6617 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Sat, 21 Nov 2020 15:19:23 +0300 Subject: [PATCH 4/6] core: allow to provide block in `GetTestVM()` Sometimes amount of GAS consumed depends on block height. --- pkg/core/blockchain.go | 4 ++-- pkg/core/blockchainer/blockchainer.go | 2 +- pkg/network/helper_test.go | 2 +- pkg/rpc/server/client_test.go | 2 +- pkg/rpc/server/server.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index cbfea1725..689874354 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1557,10 +1557,10 @@ func (bc *Blockchain) GetEnrollments() ([]state.Validator, error) { } // GetTestVM returns a VM and a Store setup for a test run of some sort of code. -func (bc *Blockchain) GetTestVM(tx *transaction.Transaction) *vm.VM { +func (bc *Blockchain) GetTestVM(tx *transaction.Transaction, b *block.Block) *vm.VM { d := bc.dao.GetWrapped().(*dao.Simple) d.MPT = nil - systemInterop := bc.newInteropContext(trigger.Application, d, nil, tx) + systemInterop := bc.newInteropContext(trigger.Application, d, b, tx) vm := systemInterop.SpawnVM() vm.SetPriceGetter(getPrice) return vm diff --git a/pkg/core/blockchainer/blockchainer.go b/pkg/core/blockchainer/blockchainer.go index 451b7941c..ce9ea4c5c 100644 --- a/pkg/core/blockchainer/blockchainer.go +++ b/pkg/core/blockchainer/blockchainer.go @@ -50,7 +50,7 @@ type Blockchainer interface { GetStateRoot(height uint32) (*state.MPTRootState, error) GetStorageItem(id int32, key []byte) *state.StorageItem GetStorageItems(id int32) (map[string]*state.StorageItem, error) - GetTestVM(tx *transaction.Transaction) *vm.VM + GetTestVM(tx *transaction.Transaction, b *block.Block) *vm.VM GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error) mempool.Feer // fee interface GetMaxBlockSize() uint32 diff --git a/pkg/network/helper_test.go b/pkg/network/helper_test.go index 1c9169ead..962073c4a 100644 --- a/pkg/network/helper_test.go +++ b/pkg/network/helper_test.go @@ -130,7 +130,7 @@ func (chain testChain) GetStateRoot(height uint32) (*state.MPTRootState, error) func (chain testChain) GetStorageItem(id int32, key []byte) *state.StorageItem { panic("TODO") } -func (chain testChain) GetTestVM(tx *transaction.Transaction) *vm.VM { +func (chain testChain) GetTestVM(tx *transaction.Transaction, b *block.Block) *vm.VM { panic("TODO") } func (chain testChain) GetStorageItems(id int32) (map[string]*state.StorageItem, error) { diff --git a/pkg/rpc/server/client_test.go b/pkg/rpc/server/client_test.go index 4fe350bc1..711db62a5 100644 --- a/pkg/rpc/server/client_test.go +++ b/pkg/rpc/server/client_test.go @@ -284,7 +284,7 @@ func TestCreateNEP5TransferTx(t *testing.T) { require.NoError(t, err) require.NoError(t, acc.SignTx(tx)) require.NoError(t, chain.VerifyTx(tx)) - v := chain.GetTestVM(tx) + v := chain.GetTestVM(tx, nil) v.LoadScriptWithFlags(tx.Script, smartcontract.All) require.NoError(t, v.Run()) } diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index f17412ba3..382e28079 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -1127,7 +1127,7 @@ func (s *Server) invokescript(reqParams request.Params) (interface{}, *response. // runScriptInVM runs given script in a new test VM and returns the invocation // result. func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) *result.Invoke { - vm := s.chain.GetTestVM(tx) + vm := s.chain.GetTestVM(tx, nil) vm.GasLimit = int64(s.config.MaxGasInvoke) vm.LoadScriptWithFlags(script, smartcontract.All) err := vm.Run() From b97dfae8d86bc047028d9a8d4424de05fbc807fc Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 19 Nov 2020 18:01:42 +0300 Subject: [PATCH 5/6] native: replace NEP-5 with NEP-17 --- cli/multisig_test.go | 2 +- cli/testdata/verify.go | 3 + cli/testdata/verify.manifest.json | 2 +- cli/testdata/verify.nef | Bin 82 -> 86 bytes examples/token-sale/token_sale.go | 8 -- examples/token-sale/token_sale.yml | 2 +- examples/token/nep5/nep5.go | 2 +- examples/token/token.go | 9 +- examples/token/token.yml | 4 +- pkg/consensus/consensus_test.go | 4 +- pkg/core/blockchain.go | 2 +- pkg/core/blockchain_test.go | 4 +- pkg/core/helper_test.go | 10 +-- pkg/core/interop_system.go | 11 +-- pkg/core/interop_system_test.go | 17 ++++ pkg/core/native/native_gas.go | 22 ++--- pkg/core/native/native_neo.go | 24 +++--- .../{native_nep5.go => native_nep17.go} | 79 ++++++++++++------ pkg/core/native/oracle.go | 18 +++- pkg/core/native_neo_test.go | 35 +++++++- pkg/rpc/client/nep5.go | 20 +---- pkg/rpc/server/client_test.go | 5 -- pkg/rpc/server/server.go | 23 +++-- pkg/rpc/server/server_test.go | 6 +- pkg/rpc/server/testdata/test_contract.go | 10 +-- pkg/rpc/server/testdata/testblocks.acc | Bin 7577 -> 7476 bytes pkg/smartcontract/manifest/manifest.go | 7 +- 27 files changed, 195 insertions(+), 134 deletions(-) rename pkg/core/native/{native_nep5.go => native_nep17.go} (72%) diff --git a/cli/multisig_test.go b/cli/multisig_test.go index c1829ec9f..9672537eb 100644 --- a/cli/multisig_test.go +++ b/cli/multisig_test.go @@ -93,7 +93,7 @@ func TestSignMultisigTx(t *testing.T) { e.Chain.GoverningTokenHash().StringLE(), "transfer", "bytes:"+multisigHash.StringBE(), "bytes:"+priv.GetScriptHash().StringBE(), - "int:1", + "int:1", "bytes:", "--", strings.Join([]string{multisigHash.StringLE(), ":", "Global"}, "")) e.In.WriteString("pass\r") diff --git a/cli/testdata/verify.go b/cli/testdata/verify.go index 467e1fd59..6a3ed7b6a 100644 --- a/cli/testdata/verify.go +++ b/cli/testdata/verify.go @@ -3,3 +3,6 @@ package testdata func Verify() bool { return true } + +func OnPayment(from []byte, amount int, data interface{}) { +} diff --git a/cli/testdata/verify.manifest.json b/cli/testdata/verify.manifest.json index 10f37f908..518bcd896 100755 --- a/cli/testdata/verify.manifest.json +++ b/cli/testdata/verify.manifest.json @@ -1 +1 @@ -{"name":"Verify","abi":{"hash":"0x8dff9f223e4622961f410c015dd37052a59892bb","methods":[{"name":"verify","offset":0,"parameters":[],"returntype":"Boolean"}],"events":[]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"safemethods":[],"extra":null} \ No newline at end of file +{"name":"verify","abi":{"hash":"0xbf214a7551e50d6fbe0bef05271719325d9fc1ef","methods":[{"name":"verify","offset":0,"parameters":[],"returntype":"Boolean"},{"name":"onPayment","offset":5,"parameters":[{"name":"from","type":"ByteArray"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void"}],"events":[]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"safemethods":[],"extra":null} \ No newline at end of file diff --git a/cli/testdata/verify.nef b/cli/testdata/verify.nef index 65f2011fb8ebd648989dcc76bfbb2734d495ed08..309796612c518d21dc13587970bab29636f5642b 100755 GIT binary patch delta 39 vcmWFvn_!~!{^0yrBS~>}*7w}|@_C;ImU=1f*GqnIn=_n|LC_(bf!P57Dp?I` delta 35 rcmWFwnqVTgd(w=hK?Rp%8F?J#rzyGFDb4@iyVrJK7;88qgP;Qd_?is4 diff --git a/examples/token-sale/token_sale.go b/examples/token-sale/token_sale.go index a69cb34a2..e48510516 100644 --- a/examples/token-sale/token_sale.go +++ b/examples/token-sale/token_sale.go @@ -133,14 +133,6 @@ func checkOwnerWitness() bool { return false } -// Name returns the token name -func Name() interface{} { - if trigger != runtime.Application { - return false - } - return token.Name -} - // Decimals returns the token decimals func Decimals() interface{} { if trigger != runtime.Application { diff --git a/examples/token-sale/token_sale.yml b/examples/token-sale/token_sale.yml index 56f3d4d9b..2d6181dca 100644 --- a/examples/token-sale/token_sale.yml +++ b/examples/token-sale/token_sale.yml @@ -1,3 +1,3 @@ name: "My awesome token" -supportedstandards: ["NEP-5"] +supportedstandards: ["NEP-17"] events: [] diff --git a/examples/token/nep5/nep5.go b/examples/token/nep5/nep5.go index f5b911953..8aeb8760c 100644 --- a/examples/token/nep5/nep5.go +++ b/examples/token/nep5/nep5.go @@ -44,7 +44,7 @@ func (t Token) BalanceOf(ctx storage.Context, holder []byte) int { } // Transfer token from one user to another -func (t Token) Transfer(ctx storage.Context, from []byte, to []byte, amount int) bool { +func (t Token) Transfer(ctx storage.Context, from []byte, to []byte, amount int, data interface{}) bool { amountFrom := t.CanTransfer(ctx, from, to, amount) if amountFrom == -1 { return false diff --git a/examples/token/token.go b/examples/token/token.go index 09107d702..bf0e187bd 100644 --- a/examples/token/token.go +++ b/examples/token/token.go @@ -32,11 +32,6 @@ func init() { ctx = storage.GetContext() } -// Name returns the token name -func Name() string { - return token.Name -} - // Symbol returns the token symbol func Symbol() string { return token.Symbol @@ -58,8 +53,8 @@ func BalanceOf(holder interop.Hash160) interface{} { } // Transfer token from one user to another -func Transfer(from interop.Hash160, to interop.Hash160, amount int) bool { - return token.Transfer(ctx, from, to, amount) +func Transfer(from interop.Hash160, to interop.Hash160, amount int, data interface{}) bool { + return token.Transfer(ctx, from, to, amount, data) } // Mint initial supply of tokens diff --git a/examples/token/token.yml b/examples/token/token.yml index b6ee7f862..cea35644b 100644 --- a/examples/token/token.yml +++ b/examples/token/token.yml @@ -1,7 +1,7 @@ name: "Awesome NEO Token" -supportedstandards: ["NEP-5"] +supportedstandards: ["NEP-17"] events: - - name: transfer + - name: Transfer parameters: - name: from type: ByteString diff --git a/pkg/consensus/consensus_test.go b/pkg/consensus/consensus_test.go index d269ad35a..3fa50fb62 100644 --- a/pkg/consensus/consensus_test.go +++ b/pkg/consensus/consensus_test.go @@ -54,10 +54,10 @@ func initServiceNextConsensus(t *testing.T, newAcc *wallet.Account, offset uint3 // Transfer funds to new validator. w := io.NewBufBinWriter() emit.AppCallWithOperationAndArgs(w.BinWriter, bc.GoverningTokenHash(), "transfer", - acc.Contract.ScriptHash().BytesBE(), newPriv.GetScriptHash().BytesBE(), int64(native.NEOTotalSupply)) + acc.Contract.ScriptHash().BytesBE(), newPriv.GetScriptHash().BytesBE(), int64(native.NEOTotalSupply), nil) emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.AppCallWithOperationAndArgs(w.BinWriter, bc.UtilityTokenHash(), "transfer", - acc.Contract.ScriptHash().BytesBE(), newPriv.GetScriptHash().BytesBE(), int64(1_000_000_000)) + acc.Contract.ScriptHash().BytesBE(), newPriv.GetScriptHash().BytesBE(), int64(1_000_000_000), nil) emit.Opcodes(w.BinWriter, opcode.ASSERT) require.NoError(t, w.Err) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 689874354..f60944887 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -758,7 +758,7 @@ func (bc *Blockchain) runPersist(script []byte, block *block.Block, cache *dao.C } func (bc *Blockchain) handleNotification(note *state.NotificationEvent, d *dao.Cached, b *block.Block, h util.Uint256) { - if note.Name != "transfer" && note.Name != "Transfer" { + if note.Name != "Transfer" { return } arr, ok := note.Item.Value().([]stackitem.Item) diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 15276ddcf..c287f7678 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -265,12 +265,12 @@ func TestVerifyTx(t *testing.T) { amount = 1_000_000_000 } emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", - neoOwner, a.Contract.ScriptHash(), amount) + neoOwner, a.Contract.ScriptHash(), amount, nil) emit.Opcodes(w.BinWriter, opcode.ASSERT) } } emit.AppCallWithOperationAndArgs(w.BinWriter, gasHash, "transfer", - neoOwner, testchain.CommitteeScriptHash(), int64(1_000_000_000)) + neoOwner, testchain.CommitteeScriptHash(), int64(1_000_000_000), nil) emit.Opcodes(w.BinWriter, opcode.ASSERT) require.NoError(t, w.Err) diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index 4fd78e494..814815b12 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -244,7 +244,7 @@ func TestCreateBasicChain(t *testing.T) { require.NoError(t, err) // Push some contract into the chain. - txDeploy, avm := newDeployTx(t, prefix+"test_contract.go") + txDeploy, avm := newDeployTx(t, prefix+"test_contract.go", "Rubl") txDeploy.Nonce = getNextNonce() txDeploy.ValidUntilBlock = validUntilBlock txDeploy.Signers = []transaction.Signer{{Account: priv0ScriptHash}} @@ -332,7 +332,7 @@ func TestCreateBasicChain(t *testing.T) { t.Logf("sendRublesTx: %v", transferTx.Hash().StringLE()) // Push verification contract into the chain. - txDeploy2, _ := newDeployTx(t, prefix+"verification_contract.go") + txDeploy2, _ := newDeployTx(t, prefix+"verification_contract.go", "Verify") txDeploy2.Nonce = getNextNonce() txDeploy2.ValidUntilBlock = validUntilBlock txDeploy2.Signers = []transaction.Signer{{Account: priv0ScriptHash}} @@ -382,14 +382,14 @@ func TestCreateBasicChain(t *testing.T) { func newNEP5Transfer(sc, from, to util.Uint160, amount int64) *transaction.Transaction { w := io.NewBufBinWriter() - emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", from, to, amount) + emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", from, to, amount, nil) emit.Opcodes(w.BinWriter, opcode.ASSERT) script := w.Bytes() return transaction.New(testchain.Network(), script, 10000000) } -func newDeployTx(t *testing.T, name string) (*transaction.Transaction, []byte) { +func newDeployTx(t *testing.T, name, ctrName string) (*transaction.Transaction, []byte) { c, err := ioutil.ReadFile(name) require.NoError(t, err) avm, di, err := compiler.CompileWithDebugInfo(name, bytes.NewReader(c)) @@ -398,7 +398,7 @@ func newDeployTx(t *testing.T, name string) (*transaction.Transaction, []byte) { t.Logf("contractScript: %x", avm) script := io.NewBufBinWriter() - m, err := di.ConvertToManifest("Test", nil) + m, err := di.ConvertToManifest(ctrName, nil) require.NoError(t, err) bs, err := json.Marshal(m) require.NoError(t, err) diff --git a/pkg/core/interop_system.go b/pkg/core/interop_system.go index c24dcd974..31822df6a 100644 --- a/pkg/core/interop_system.go +++ b/pkg/core/interop_system.go @@ -299,16 +299,7 @@ func runtimeLog(ic *interop.Context) error { // runtimeGetTime returns timestamp of the block being verified, or the latest // one in the blockchain if no block is given to Context. func runtimeGetTime(ic *interop.Context) error { - var header *block.Header - if ic.Block == nil { - var err error - header, err = ic.Chain.GetHeader(ic.Chain.CurrentBlockHash()) - if err != nil { - return err - } - } else { - header = ic.Block.Header() - } + header := ic.Block.Header() ic.VM.Estack().PushVal(header.Timestamp) return nil } diff --git a/pkg/core/interop_system_test.go b/pkg/core/interop_system_test.go index a382afbda..f714b855f 100644 --- a/pkg/core/interop_system_test.go +++ b/pkg/core/interop_system_test.go @@ -408,6 +408,13 @@ func getTestContractState() (*state.Contract, *state.Contract) { emit.String(w.BinWriter, "initial") emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) emit.Syscall(w.BinWriter, interopnames.SystemStorageGet) + emit.Opcodes(w.BinWriter, opcode.RET) + onPaymentOff := w.Len() + emit.Int(w.BinWriter, 3) + emit.Opcodes(w.BinWriter, opcode.PACK) + emit.String(w.BinWriter, "LastPayment") + emit.Syscall(w.BinWriter, interopnames.SystemRuntimeNotify) + emit.Opcodes(w.BinWriter, opcode.RET) script := w.Bytes() h := hash.Hash160(script) @@ -482,6 +489,16 @@ func getTestContractState() (*state.Contract, *state.Contract) { }, ReturnType: smartcontract.VoidType, }, + { + Name: "onPayment", + Offset: onPaymentOff, + Parameters: []manifest.Parameter{ + manifest.NewParameter("from", smartcontract.Hash160Type), + manifest.NewParameter("amount", smartcontract.IntegerType), + manifest.NewParameter("data", smartcontract.AnyType), + }, + ReturnType: smartcontract.VoidType, + }, } cs := &state.Contract{ Script: script, diff --git a/pkg/core/native/native_gas.go b/pkg/core/native/native_gas.go index 2913ed45e..baaed669f 100644 --- a/pkg/core/native/native_gas.go +++ b/pkg/core/native/native_gas.go @@ -13,7 +13,7 @@ import ( // GAS represents GAS native contract. type GAS struct { - nep5TokenNative + nep17TokenNative NEO *NEO } @@ -27,15 +27,15 @@ const initialGAS = 30000000 // newGAS returns GAS native contract. func newGAS() *GAS { g := &GAS{} - nep5 := newNEP5Native(gasName) - nep5.symbol = "gas" - nep5.decimals = 8 - nep5.factor = GASFactor - nep5.onPersist = chainOnPersist(nep5.OnPersist, g.OnPersist) - nep5.incBalance = g.increaseBalance - nep5.ContractID = gasContractID + nep17 := newNEP17Native(gasName) + nep17.symbol = "gas" + nep17.decimals = 8 + nep17.factor = GASFactor + nep17.onPersist = chainOnPersist(nep17.OnPersist, g.OnPersist) + nep17.incBalance = g.increaseBalance + nep17.ContractID = gasContractID - g.nep5TokenNative = *nep5 + g.nep17TokenNative = *nep17 onp := g.Methods["onPersist"] onp.Func = getOnPersistWrapper(g.onPersist) @@ -65,10 +65,10 @@ func (g *GAS) increaseBalance(_ *interop.Context, _ util.Uint160, si *state.Stor // Initialize initializes GAS contract. func (g *GAS) Initialize(ic *interop.Context) error { - if err := g.nep5TokenNative.Initialize(ic); err != nil { + if err := g.nep17TokenNative.Initialize(ic); err != nil { return err } - if g.nep5TokenNative.getTotalSupply(ic.DAO).Sign() != 0 { + if g.nep17TokenNative.getTotalSupply(ic.DAO).Sign() != 0 { return errors.New("already initialized") } h, err := getStandbyValidatorsHash(ic) diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index 05031838d..76004775b 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -28,7 +28,7 @@ import ( // NEO represents NEO native contract. type NEO struct { - nep5TokenNative + nep17TokenNative GAS *GAS // gasPerBlock represents current value of generated gas per block. @@ -93,16 +93,16 @@ func makeValidatorKey(key *keys.PublicKey) []byte { // newNEO returns NEO native contract. func newNEO() *NEO { n := &NEO{} - nep5 := newNEP5Native(neoName) - nep5.symbol = "neo" - nep5.decimals = 0 - nep5.factor = 1 - nep5.onPersist = chainOnPersist(nep5.OnPersist, n.OnPersist) - nep5.postPersist = chainOnPersist(nep5.postPersist, n.PostPersist) - nep5.incBalance = n.increaseBalance - nep5.ContractID = neoContractID + nep17 := newNEP17Native(neoName) + nep17.symbol = "neo" + nep17.decimals = 0 + nep17.factor = 1 + nep17.onPersist = chainOnPersist(nep17.OnPersist, n.OnPersist) + nep17.postPersist = chainOnPersist(nep17.postPersist, n.PostPersist) + nep17.incBalance = n.increaseBalance + nep17.ContractID = neoContractID - n.nep5TokenNative = *nep5 + n.nep17TokenNative = *nep17 n.votesChanged.Store(true) n.nextValidators.Store(keys.PublicKeys(nil)) n.validators.Store(keys.PublicKeys(nil)) @@ -165,11 +165,11 @@ func newNEO() *NEO { // Initialize initializes NEO contract. func (n *NEO) Initialize(ic *interop.Context) error { - if err := n.nep5TokenNative.Initialize(ic); err != nil { + if err := n.nep17TokenNative.Initialize(ic); err != nil { return err } - if n.nep5TokenNative.getTotalSupply(ic.DAO).Sign() != 0 { + if n.nep17TokenNative.getTotalSupply(ic.DAO).Sign() != 0 { return errors.New("already initialized") } diff --git a/pkg/core/native/native_nep5.go b/pkg/core/native/native_nep17.go similarity index 72% rename from pkg/core/native/native_nep5.go rename to pkg/core/native/native_nep17.go index 76ecb5d7c..bfc588171 100644 --- a/pkg/core/native/native_nep5.go +++ b/pkg/core/native/native_nep17.go @@ -7,6 +7,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/interop" + "github.com/nspcc-dev/neo-go/pkg/core/interop/contract" "github.com/nspcc-dev/neo-go/pkg/core/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint" @@ -14,6 +15,7 @@ import ( "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/stackitem" ) @@ -28,8 +30,8 @@ func makeAccountKey(h util.Uint160) []byte { return k } -// nep5TokenNative represents NEP-5 token contract. -type nep5TokenNative struct { +// nep17TokenNative represents NEP-17 token contract. +type nep17TokenNative struct { interop.ContractMD symbol string decimals int64 @@ -42,15 +44,15 @@ type nep5TokenNative struct { // totalSupplyKey is the key used to store totalSupply value. var totalSupplyKey = []byte{11} -func (c *nep5TokenNative) Metadata() *interop.ContractMD { +func (c *nep17TokenNative) Metadata() *interop.ContractMD { return &c.ContractMD } -var _ interop.Contract = (*nep5TokenNative)(nil) +var _ interop.Contract = (*nep17TokenNative)(nil) -func newNEP5Native(name string) *nep5TokenNative { - n := &nep5TokenNative{ContractMD: *interop.NewContractMD(name)} - n.Manifest.SupportedStandards = []string{manifest.NEP5StandardName} +func newNEP17Native(name string) *nep17TokenNative { + n := &nep17TokenNative{ContractMD: *interop.NewContractMD(name)} + n.Manifest.SupportedStandards = []string{manifest.NEP17StandardName} desc := newDescriptor("name", smartcontract.StringType) md := newMethodAndPrice(nameMethod(name), 0, smartcontract.NoneFlag) @@ -77,6 +79,7 @@ func newNEP5Native(name string) *nep5TokenNative { manifest.NewParameter("from", smartcontract.Hash160Type), manifest.NewParameter("to", smartcontract.Hash160Type), manifest.NewParameter("amount", smartcontract.IntegerType), + manifest.NewParameter("data", smartcontract.AnyType), ) md = newMethodAndPrice(n.Transfer, 8000000, smartcontract.AllowModifyStates) n.AddMethod(md, desc, false) @@ -94,23 +97,23 @@ func newNEP5Native(name string) *nep5TokenNative { return n } -func (c *nep5TokenNative) Initialize(_ *interop.Context) error { +func (c *nep17TokenNative) Initialize(_ *interop.Context) error { return nil } -func (c *nep5TokenNative) Symbol(_ *interop.Context, _ []stackitem.Item) stackitem.Item { +func (c *nep17TokenNative) Symbol(_ *interop.Context, _ []stackitem.Item) stackitem.Item { return stackitem.NewByteArray([]byte(c.symbol)) } -func (c *nep5TokenNative) Decimals(_ *interop.Context, _ []stackitem.Item) stackitem.Item { +func (c *nep17TokenNative) Decimals(_ *interop.Context, _ []stackitem.Item) stackitem.Item { return stackitem.NewBigInteger(big.NewInt(c.decimals)) } -func (c *nep5TokenNative) TotalSupply(ic *interop.Context, _ []stackitem.Item) stackitem.Item { +func (c *nep17TokenNative) TotalSupply(ic *interop.Context, _ []stackitem.Item) stackitem.Item { return stackitem.NewBigInteger(c.getTotalSupply(ic.DAO)) } -func (c *nep5TokenNative) getTotalSupply(d dao.DAO) *big.Int { +func (c *nep17TokenNative) getTotalSupply(d dao.DAO) *big.Int { si := d.GetStorageItem(c.ContractID, totalSupplyKey) if si == nil { return big.NewInt(0) @@ -118,16 +121,16 @@ func (c *nep5TokenNative) getTotalSupply(d dao.DAO) *big.Int { return bigint.FromBytes(si.Value) } -func (c *nep5TokenNative) saveTotalSupply(d dao.DAO, supply *big.Int) error { +func (c *nep17TokenNative) saveTotalSupply(d dao.DAO, supply *big.Int) error { si := &state.StorageItem{Value: bigint.ToBytes(supply)} return d.PutStorageItem(c.ContractID, totalSupplyKey, si) } -func (c *nep5TokenNative) Transfer(ic *interop.Context, args []stackitem.Item) stackitem.Item { +func (c *nep17TokenNative) Transfer(ic *interop.Context, args []stackitem.Item) stackitem.Item { from := toUint160(args[0]) to := toUint160(args[1]) amount := toBigInt(args[2]) - err := c.TransferInternal(ic, from, to, amount) + err := c.TransferInternal(ic, from, to, amount, args[3]) return stackitem.NewBool(err == nil) } @@ -138,7 +141,31 @@ func addrToStackItem(u *util.Uint160) stackitem.Item { return stackitem.NewByteArray(u.BytesBE()) } -func (c *nep5TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint160, amount *big.Int) { +func (c *nep17TokenNative) postTransfer(ic *interop.Context, from, to *util.Uint160, amount *big.Int, data stackitem.Item) { + c.emitTransfer(ic, from, to, amount) + if to == nil { + return + } + cs, err := ic.DAO.GetContractState(*to) + if err != nil { + return + } + + fromArg := stackitem.Item(stackitem.Null{}) + if from != nil { + fromArg = stackitem.NewByteArray((*from).BytesBE()) + } + args := []stackitem.Item{ + fromArg, + stackitem.NewBigInteger(amount), + data, + } + if err := contract.CallExInternal(ic, cs, manifest.MethodOnPayment, args, smartcontract.All, vm.EnsureIsEmpty); err != nil { + panic(err) + } +} + +func (c *nep17TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint160, amount *big.Int) { ne := state.NotificationEvent{ ScriptHash: c.Hash, Name: "Transfer", @@ -151,7 +178,7 @@ func (c *nep5TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint1 ic.Notifications = append(ic.Notifications, ne) } -func (c *nep5TokenNative) updateAccBalance(ic *interop.Context, acc util.Uint160, amount *big.Int) error { +func (c *nep17TokenNative) updateAccBalance(ic *interop.Context, acc util.Uint160, amount *big.Int) error { key := makeAccountKey(acc) si := ic.DAO.GetStorageItem(c.ContractID, key) if si == nil { @@ -174,7 +201,7 @@ func (c *nep5TokenNative) updateAccBalance(ic *interop.Context, acc util.Uint160 } // TransferInternal transfers NEO between accounts. -func (c *nep5TokenNative) TransferInternal(ic *interop.Context, from, to util.Uint160, amount *big.Int) error { +func (c *nep17TokenNative) TransferInternal(ic *interop.Context, from, to util.Uint160, amount *big.Int, data stackitem.Item) error { if amount.Sign() == -1 { return errors.New("negative amount") } @@ -205,11 +232,11 @@ func (c *nep5TokenNative) TransferInternal(ic *interop.Context, from, to util.Ui } } - c.emitTransfer(ic, &from, &to, amount) + c.postTransfer(ic, &from, &to, amount, data) return nil } -func (c *nep5TokenNative) balanceOf(ic *interop.Context, args []stackitem.Item) stackitem.Item { +func (c *nep17TokenNative) balanceOf(ic *interop.Context, args []stackitem.Item) stackitem.Item { h := toUint160(args[0]) bs, err := ic.DAO.GetNEP5Balances(h) if err != nil { @@ -219,23 +246,23 @@ func (c *nep5TokenNative) balanceOf(ic *interop.Context, args []stackitem.Item) return stackitem.NewBigInteger(&balance) } -func (c *nep5TokenNative) mint(ic *interop.Context, h util.Uint160, amount *big.Int) { +func (c *nep17TokenNative) mint(ic *interop.Context, h util.Uint160, amount *big.Int) { if amount.Sign() == 0 { return } c.addTokens(ic, h, amount) - c.emitTransfer(ic, nil, &h, amount) + c.postTransfer(ic, nil, &h, amount, stackitem.Null{}) } -func (c *nep5TokenNative) burn(ic *interop.Context, h util.Uint160, amount *big.Int) { +func (c *nep17TokenNative) burn(ic *interop.Context, h util.Uint160, amount *big.Int) { if amount.Sign() == 0 { return } c.addTokens(ic, h, new(big.Int).Neg(amount)) - c.emitTransfer(ic, &h, nil, amount) + c.postTransfer(ic, &h, nil, amount, stackitem.Null{}) } -func (c *nep5TokenNative) addTokens(ic *interop.Context, h util.Uint160, amount *big.Int) { +func (c *nep17TokenNative) addTokens(ic *interop.Context, h util.Uint160, amount *big.Int) { if amount.Sign() == 0 { return } @@ -260,7 +287,7 @@ func (c *nep5TokenNative) addTokens(ic *interop.Context, h util.Uint160, amount } } -func (c *nep5TokenNative) OnPersist(ic *interop.Context) error { +func (c *nep17TokenNative) OnPersist(ic *interop.Context) error { if ic.Trigger != trigger.OnPersist { return errors.New("onPersist must be triggerred by system") } diff --git a/pkg/core/native/oracle.go b/pkg/core/native/oracle.go index 313a78805..d94f6a693 100644 --- a/pkg/core/native/oracle.go +++ b/pkg/core/native/oracle.go @@ -125,6 +125,13 @@ func newOracle() *Oracle { md = newMethodAndPrice(o.verify, 100_0000, smartcontract.NoneFlag) o.AddMethod(md, desc, false) + desc = newDescriptor("onPayment", smartcontract.VoidType, + manifest.NewParameter("from", smartcontract.Hash160Type), + manifest.NewParameter("amount", smartcontract.IntegerType), + manifest.NewParameter("data", smartcontract.AnyType)) + md = newMethodAndPrice(o.onPayment, 0, smartcontract.NoneFlag) + o.AddMethod(md, desc, false) + pp := chainOnPersist(postPersistBase, o.PostPersist) desc = newDescriptor("postPersist", smartcontract.VoidType) md = newMethodAndPrice(getOnPersistWrapper(pp), 0, smartcontract.AllowModifyStates) @@ -299,6 +306,7 @@ func (o *Oracle) RequestInternal(ic *interop.Context, url string, filter *string if !ic.VM.AddGas(gas.Int64()) { return ErrNotEnoughGas } + callingHash := ic.VM.GetCallingScriptHash() o.GAS.mint(ic, o.Hash, gas) si := ic.DAO.GetStorageItem(o.ContractID, prefixRequestID) id := binary.LittleEndian.Uint64(si.Value) + 1 @@ -344,7 +352,7 @@ func (o *Oracle) RequestInternal(ic *interop.Context, url string, filter *string GasForResponse: gas.Uint64(), URL: url, Filter: filter, - CallbackContract: ic.VM.GetCallingScriptHash(), + CallbackContract: callingHash, CallbackMethod: cb, UserData: data, } @@ -402,6 +410,14 @@ func (o *Oracle) verify(ic *interop.Context, _ []stackitem.Item) stackitem.Item return stackitem.NewBool(ic.Tx.HasAttribute(transaction.OracleResponseT)) } +func (o *Oracle) onPayment(ic *interop.Context, _ []stackitem.Item) stackitem.Item { + // FIXME when calling native transfer directly, context is not provided. + if h := ic.VM.GetCallingScriptHash(); h != o.Hash && h != o.GAS.Hash { + panic("only GAS can be accepted") + } + return stackitem.Null{} +} + func (o *Oracle) getOriginalTxID(d dao.DAO, tx *transaction.Transaction) util.Uint256 { for i := range tx.Attributes { if tx.Attributes[i].Type == transaction.OracleResponseT { diff --git a/pkg/core/native_neo_test.go b/pkg/core/native_neo_test.go index 4ae1d4b5e..977b514cc 100644 --- a/pkg/core/native_neo_test.go +++ b/pkg/core/native_neo_test.go @@ -16,6 +16,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/vm" "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/wallet" "github.com/stretchr/testify/require" ) @@ -76,11 +77,11 @@ func TestNEO_Vote(t *testing.T) { w := io.NewBufBinWriter() emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.NEO.Hash, "transfer", neoOwner.BytesBE(), to.BytesBE(), - big.NewInt(int64(sz-i)*1000000).Int64()) + big.NewInt(int64(sz-i)*1000000).Int64(), nil) emit.Opcodes(w.BinWriter, opcode.ASSERT) emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.GAS.Hash, "transfer", neoOwner.BytesBE(), to.BytesBE(), - int64(1_000_000_000)) + int64(1_000_000_000), nil) emit.Opcodes(w.BinWriter, opcode.ASSERT) require.NoError(t, w.Err) tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 1000_000_000) @@ -141,7 +142,7 @@ func TestNEO_Vote(t *testing.T) { gasBalance[i] = bc.GetUtilityTokenBalance(h) neoBalance[i], _ = bc.GetGoverningTokenBalance(h) emit.AppCallWithOperationAndArgs(w.BinWriter, bc.contracts.NEO.Hash, "transfer", - h.BytesBE(), h.BytesBE(), int64(1)) + h.BytesBE(), h.BytesBE(), int64(1), nil) emit.Opcodes(w.BinWriter, opcode.ASSERT) require.NoError(t, w.Err) tx := transaction.New(netmode.UnitTestNet, w.Bytes(), 0) @@ -303,3 +304,31 @@ func TestNEO_CommitteeBountyOnPersist(t *testing.T) { checkBalances() } } + +func TestNEO_TransferOnPayment(t *testing.T) { + bc := newTestChain(t) + defer bc.Close() + + cs, _ := getTestContractState() + require.NoError(t, bc.dao.PutContractState(cs)) + + const amount = 2 + tx := newNEP5Transfer(bc.contracts.NEO.Hash, neoOwner, cs.ScriptHash(), amount) + tx.SystemFee += 1_000_000 + tx.NetworkFee = 10_000_000 + tx.ValidUntilBlock = bc.BlockHeight() + 1 + addSigners(tx) + require.NoError(t, signTx(bc, tx)) + require.NoError(t, bc.AddBlock(bc.newBlock(tx))) + + aer, err := bc.GetAppExecResults(tx.Hash(), trigger.Application) + require.NoError(t, err) + require.Equal(t, vm.HaltState, aer[0].VMState) + require.Len(t, aer[0].Events, 3) // transfer + auto GAS claim + onPayment + + e := aer[0].Events[2] + require.Equal(t, "LastPayment", e.Name) + arr := e.Item.Value().([]stackitem.Item) + require.Equal(t, neoOwner.BytesBE(), arr[0].Value()) + require.Equal(t, big.NewInt(amount), arr[1].Value()) +} diff --git a/pkg/rpc/client/nep5.go b/pkg/rpc/client/nep5.go index ea8db995a..9c5a08cf1 100644 --- a/pkg/rpc/client/nep5.go +++ b/pkg/rpc/client/nep5.go @@ -37,20 +37,6 @@ func (c *Client) NEP5Decimals(tokenHash util.Uint160) (int64, error) { return topIntFromStack(result.Stack) } -// NEP5Name invokes `name` NEP5 method on a specified contract. -func (c *Client) NEP5Name(tokenHash util.Uint160) (string, error) { - result, err := c.InvokeFunction(tokenHash, "name", []smartcontract.Parameter{}, nil) - if err != nil { - return "", err - } - err = getInvocationError(result) - if err != nil { - return "", fmt.Errorf("failed to get NEP5 name: %w", err) - } - - return topStringFromStack(result.Stack) -} - // NEP5Symbol invokes `symbol` NEP5 method on a specified contract. func (c *Client) NEP5Symbol(tokenHash util.Uint160) (string, error) { result, err := c.InvokeFunction(tokenHash, "symbol", []smartcontract.Parameter{}, nil) @@ -98,7 +84,7 @@ func (c *Client) NEP5BalanceOf(tokenHash, acc util.Uint160) (int64, error) { // NEP5TokenInfo returns full NEP5 token info. func (c *Client) NEP5TokenInfo(tokenHash util.Uint160) (*wallet.Token, error) { - name, err := c.NEP5Name(tokenHash) + cs, err := c.GetContractStateByHash(tokenHash) if err != nil { return nil, err } @@ -110,7 +96,7 @@ func (c *Client) NEP5TokenInfo(tokenHash util.Uint160) (*wallet.Token, error) { if err != nil { return nil, err } - return wallet.NewToken(tokenHash, name, symbol, decimals), nil + return wallet.NewToken(tokenHash, cs.Manifest.Name, symbol, decimals), nil } // CreateNEP5TransferTx creates an invocation transaction for the 'transfer' @@ -135,7 +121,7 @@ func (c *Client) CreateNEP5MultiTransferTx(acc *wallet.Account, gas int64, recip w := io.NewBufBinWriter() for i := range recipients { emit.AppCallWithOperationAndArgs(w.BinWriter, recipients[i].Token, "transfer", from, - recipients[i].Address, recipients[i].Amount) + recipients[i].Address, recipients[i].Amount, nil) emit.Opcodes(w.BinWriter, opcode.ASSERT) } return c.CreateTxFromScript(w.Bytes(), acc, -1, gas, transaction.Signer{ diff --git a/pkg/rpc/server/client_test.go b/pkg/rpc/server/client_test.go index 711db62a5..07a3cf5ed 100644 --- a/pkg/rpc/server/client_test.go +++ b/pkg/rpc/server/client_test.go @@ -41,11 +41,6 @@ func TestClient_NEP5(t *testing.T) { require.NoError(t, err) require.EqualValues(t, 1_000_000, s) }) - t.Run("Name", func(t *testing.T) { - name, err := c.NEP5Name(h) - require.NoError(t, err) - require.Equal(t, "Rubl", name) - }) t.Run("Symbol", func(t *testing.T) { sym, err := c.NEP5Symbol(h) require.NoError(t, err) diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 382e28079..fb958318f 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -1095,7 +1095,7 @@ func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *respons return nil, response.NewInternalServerError("can't create invocation script", err) } tx.Script = script - return s.runScriptInVM(script, tx), nil + return s.runScriptInVM(script, tx) } // invokescript implements the `invokescript` RPC call. @@ -1121,16 +1121,27 @@ func (s *Server) invokescript(reqParams request.Params) (interface{}, *response. tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.None}} } tx.Script = script - return s.runScriptInVM(script, tx), nil + return s.runScriptInVM(script, tx) } // runScriptInVM runs given script in a new test VM and returns the invocation // result. -func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) *result.Invoke { - vm := s.chain.GetTestVM(tx, nil) +func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) (*result.Invoke, *response.Error) { + // When transfering funds, script execution does no auto GAS claim, + // because it depends on persisting tx height. + // This is why we provide block here. + b := block.New(s.network, s.stateRootEnabled) + b.Index = s.chain.BlockHeight() + 1 + hdr, err := s.chain.GetHeader(s.chain.GetHeaderHash(int(s.chain.BlockHeight()))) + if err != nil { + return nil, response.NewInternalServerError("can't get last block", err) + } + b.Timestamp = hdr.Timestamp + uint64(s.chain.GetConfig().SecondsPerBlock*int(time.Second/time.Millisecond)) + + vm := s.chain.GetTestVM(tx, b) vm.GasLimit = int64(s.config.MaxGasInvoke) vm.LoadScriptWithFlags(script, smartcontract.All) - err := vm.Run() + err = vm.Run() var faultException string if err != nil { faultException = err.Error() @@ -1142,7 +1153,7 @@ func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) *resu Stack: vm.Estack().ToArray(), FaultException: faultException, } - return result + return result, nil } // submitBlock broadcasts a raw block over the NEO network. diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index 4456efa06..2ddf37a25 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -56,8 +56,8 @@ type rpcTestCase struct { check func(t *testing.T, e *executor, result interface{}) } -const testContractHash = "b0fda4dd46b8e5d207e86e774a4a133c6db69ee7" -const deploymentTxHash = "59f7b22b90e26f883a56b916c1580e3ee4f13caded686353cd77577e6194c173" +const testContractHash = "55b692ecc09f240355e042c6c07e8f3fe57546b1" +const deploymentTxHash = "99e40e5d169eb9a2b6faebc6fc596c050cf3f8a70ad25de8f44309bc8ccbfbfb" const genesisBlockHash = "a496577895eb8c227bb866dc44f99f21c0cf06417ca8f2a877cc5d761a50dac0" const verifyContractHash = "c1213693b22cb0454a436d6e0bd76b8c0a3bfdf7" @@ -1345,7 +1345,7 @@ func checkNep5Balances(t *testing.T, e *executor, acc interface{}) { }, { Asset: e.chain.UtilityTokenHash(), - Amount: "80009641770", + Amount: "80009744770", LastUpdated: 7, }}, Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(), diff --git a/pkg/rpc/server/testdata/test_contract.go b/pkg/rpc/server/testdata/test_contract.go index 38ccd62f0..60b7909a4 100644 --- a/pkg/rpc/server/testdata/test_contract.go +++ b/pkg/rpc/server/testdata/test_contract.go @@ -15,11 +15,11 @@ func Init() bool { h := runtime.GetExecutingScriptHash() amount := totalSupply storage.Put(ctx, h, amount) - runtime.Notify("transfer", []byte{}, h, amount) + runtime.Notify("Transfer", []byte{}, h, amount) return true } -func Transfer(from, to []byte, amount int) bool { +func Transfer(from, to []byte, amount int, data interface{}) bool { ctx := storage.GetContext() if len(from) != 20 { runtime.Log("invalid 'from' address") @@ -54,7 +54,7 @@ func Transfer(from, to []byte, amount int) bool { toBalance += amount storage.Put(ctx, to, toBalance) - runtime.Notify("transfer", from, to, amount) + runtime.Notify("Transfer", from, to, amount) return true } @@ -74,10 +74,6 @@ func BalanceOf(addr []byte) int { return amount } -func Name() string { - return "Rubl" -} - func Symbol() string { return "RUB" } diff --git a/pkg/rpc/server/testdata/testblocks.acc b/pkg/rpc/server/testdata/testblocks.acc index 722d3c9a88c6b68ab978a98ad131d035eaeeea2a..1a29ce8cc5670425fdeacdb7ee190458c1ce33a5 100644 GIT binary patch delta 3444 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 OFnmYpPJBD;+P?q*_9K4) diff --git a/pkg/smartcontract/manifest/manifest.go b/pkg/smartcontract/manifest/manifest.go index fa72ea16b..89de8dbd4 100644 --- a/pkg/smartcontract/manifest/manifest.go +++ b/pkg/smartcontract/manifest/manifest.go @@ -20,10 +20,13 @@ const ( // MethodVerify is a name for default verification method. MethodVerify = "verify" - // NEP5StandardName represents the name of NEP5 smartcontract standard. - NEP5StandardName = "NEP-5" + // MethodOnPayment is name of the method which is called when contract receives funds. + MethodOnPayment = "onPayment" + // NEP10StandardName represents the name of NEP10 smartcontract standard. NEP10StandardName = "NEP-10" + // NEP17StandardName represents the name of NEP17 smartcontract standard. + NEP17StandardName = "NEP-17" ) // ABI represents a contract application binary interface. From 31eca342ebdb49a73e65a0442042a0122623656b Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 24 Nov 2020 11:14:25 +0300 Subject: [PATCH 6/6] *: replace all NEP5 occurences to NEP17 --- cli/candidate_test.go | 2 +- cli/multisig_test.go | 4 +- cli/{nep5_test.go => nep17_test.go} | 26 ++++---- cli/wallet/{nep5.go => nep17.go} | 48 +++++++------- cli/wallet/wallet.go | 8 +-- cli/wallet_test.go | 6 +- docs/rpc.md | 12 ++-- .../token/{nep5/nep5.go => nep17/nep17.go} | 2 +- examples/token/token.go | 6 +- pkg/core/blockchain.go | 36 +++++----- pkg/core/blockchain_test.go | 2 +- pkg/core/blockchainer/blockchainer.go | 4 +- pkg/core/dao/cacheddao.go | 48 +++++++------- pkg/core/dao/dao.go | 64 +++++++++--------- pkg/core/helper_test.go | 14 ++-- pkg/core/native/native_gas.go | 2 +- pkg/core/native/native_nep17.go | 2 +- pkg/core/native_neo_test.go | 2 +- pkg/core/state/native_state.go | 26 ++++---- pkg/core/state/{nep5.go => nep17.go} | 56 ++++++++-------- .../state/{nep5_test.go => nep17_test.go} | 24 +++---- pkg/core/storage/store.go | 4 +- pkg/network/helper_test.go | 4 +- pkg/rpc/client/doc.go | 4 +- pkg/rpc/client/doc_test.go | 2 +- pkg/rpc/client/{nep5.go => nep17.go} | 58 ++++++++-------- pkg/rpc/client/rpc.go | 16 ++--- pkg/rpc/client/rpc_test.go | 46 ++++++------- pkg/rpc/response/result/{nep5.go => nep17.go} | 26 ++++---- pkg/rpc/server/client_test.go | 16 ++--- pkg/rpc/server/server.go | 28 ++++---- pkg/rpc/server/server_test.go | 66 +++++++++---------- pkg/wallet/token_test.go | 6 +- 33 files changed, 335 insertions(+), 335 deletions(-) rename cli/{nep5_test.go => nep17_test.go} (91%) rename cli/wallet/{nep5.go => nep17.go} (91%) rename examples/token/{nep5/nep5.go => nep17/nep17.go} (99%) rename pkg/core/state/{nep5.go => nep17.go} (70%) rename pkg/core/state/{nep5_test.go => nep17_test.go} (68%) rename pkg/rpc/client/{nep5.go => nep17.go} (70%) rename pkg/rpc/response/result/{nep5.go => nep17.go} (52%) diff --git a/cli/candidate_test.go b/cli/candidate_test.go index 4358b992b..3018754d9 100644 --- a/cli/candidate_test.go +++ b/cli/candidate_test.go @@ -16,7 +16,7 @@ func TestRegisterCandidate(t *testing.T) { defer e.Close(t) e.In.WriteString("one\r") - e.Run(t, "neo-go", "wallet", "nep5", "multitransfer", + e.Run(t, "neo-go", "wallet", "nep17", "multitransfer", "--rpc-endpoint", "http://"+e.RPC.Addr, "--wallet", validatorWallet, "--from", validatorAddr, diff --git a/cli/multisig_test.go b/cli/multisig_test.go index 9672537eb..d8aebfef5 100644 --- a/cli/multisig_test.go +++ b/cli/multisig_test.go @@ -51,7 +51,7 @@ func TestSignMultisigTx(t *testing.T) { // Transfer funds to the multisig. e.In.WriteString("one\r") - e.Run(t, "neo-go", "wallet", "nep5", "multitransfer", + e.Run(t, "neo-go", "wallet", "nep17", "multitransfer", "--rpc-endpoint", "http://"+e.RPC.Addr, "--wallet", validatorWallet, "--from", validatorAddr, @@ -66,7 +66,7 @@ func TestSignMultisigTx(t *testing.T) { txPath := path.Join(tmpDir, "multisigtx.json") defer os.Remove(txPath) e.In.WriteString("pass\r") - e.Run(t, "neo-go", "wallet", "nep5", "transfer", + e.Run(t, "neo-go", "wallet", "nep17", "transfer", "--rpc-endpoint", "http://"+e.RPC.Addr, "--wallet", wallet1Path, "--from", multisigAddr, "--to", priv.Address(), "--token", "neo", "--amount", "1", diff --git a/cli/nep5_test.go b/cli/nep17_test.go similarity index 91% rename from cli/nep5_test.go rename to cli/nep17_test.go index cf6b2f4a1..78ecb478c 100644 --- a/cli/nep5_test.go +++ b/cli/nep17_test.go @@ -15,10 +15,10 @@ import ( "github.com/stretchr/testify/require" ) -func TestNEP5Balance(t *testing.T) { +func TestNEP17Balance(t *testing.T) { e := newExecutor(t, true) defer e.Close(t) - cmdbalance := []string{"neo-go", "wallet", "nep5", "balance"} + cmdbalance := []string{"neo-go", "wallet", "nep17", "balance"} cmdbase := append(cmdbalance, "--rpc-endpoint", "http://"+e.RPC.Addr, "--wallet", validatorWallet, @@ -99,7 +99,7 @@ func TestNEP5Balance(t *testing.T) { return } -func TestNEP5Transfer(t *testing.T) { +func TestNEP17Transfer(t *testing.T) { w, err := wallet.NewWalletFromFile("testdata/testwallet.json") require.NoError(t, err) defer w.Close() @@ -107,7 +107,7 @@ func TestNEP5Transfer(t *testing.T) { e := newExecutor(t, true) defer e.Close(t) args := []string{ - "neo-go", "wallet", "nep5", "transfer", + "neo-go", "wallet", "nep17", "transfer", "--rpc-endpoint", "http://" + e.RPC.Addr, "--wallet", validatorWallet, "--from", validatorAddr, @@ -132,7 +132,7 @@ func TestNEP5Transfer(t *testing.T) { require.Equal(t, big.NewInt(1), b) } -func TestNEP5MultiTransfer(t *testing.T) { +func TestNEP17MultiTransfer(t *testing.T) { privs, _ := generateKeys(t, 3) e := newExecutor(t, true) @@ -140,7 +140,7 @@ func TestNEP5MultiTransfer(t *testing.T) { neoContractHash, err := e.Chain.GetNativeContractScriptHash("neo") require.NoError(t, err) args := []string{ - "neo-go", "wallet", "nep5", "multitransfer", + "neo-go", "wallet", "nep17", "multitransfer", "--rpc-endpoint", "http://" + e.RPC.Addr, "--wallet", validatorWallet, "--from", validatorAddr, @@ -161,7 +161,7 @@ func TestNEP5MultiTransfer(t *testing.T) { require.Equal(t, big.NewInt(13), b) } -func TestNEP5ImportToken(t *testing.T) { +func TestNEP17ImportToken(t *testing.T) { e := newExecutor(t, true) defer e.Close(t) @@ -174,11 +174,11 @@ func TestNEP5ImportToken(t *testing.T) { gasContractHash, err := e.Chain.GetNativeContractScriptHash("gas") require.NoError(t, err) e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath) - e.Run(t, "neo-go", "wallet", "nep5", "import", + e.Run(t, "neo-go", "wallet", "nep17", "import", "--rpc-endpoint", "http://"+e.RPC.Addr, "--wallet", walletPath, "--token", gasContractHash.StringLE()) - e.Run(t, "neo-go", "wallet", "nep5", "import", + e.Run(t, "neo-go", "wallet", "nep17", "import", "--rpc-endpoint", "http://"+e.RPC.Addr, "--wallet", walletPath, "--token", neoContractHash.StringLE()) @@ -192,12 +192,12 @@ func TestNEP5ImportToken(t *testing.T) { e.checkNextLine(t, "^Address:\\s*"+address.Uint160ToString(gasContractHash)) } t.Run("WithToken", func(t *testing.T) { - e.Run(t, "neo-go", "wallet", "nep5", "info", + e.Run(t, "neo-go", "wallet", "nep17", "info", "--wallet", walletPath, "--token", gasContractHash.StringLE()) checkGASInfo(t) }) t.Run("NoToken", func(t *testing.T) { - e.Run(t, "neo-go", "wallet", "nep5", "info", + e.Run(t, "neo-go", "wallet", "nep17", "info", "--wallet", walletPath) checkGASInfo(t) _, err := e.Out.ReadString('\n') @@ -210,9 +210,9 @@ func TestNEP5ImportToken(t *testing.T) { }) t.Run("Remove", func(t *testing.T) { e.In.WriteString("y\r") - e.Run(t, "neo-go", "wallet", "nep5", "remove", + e.Run(t, "neo-go", "wallet", "nep17", "remove", "--wallet", walletPath, "--token", neoContractHash.StringLE()) - e.Run(t, "neo-go", "wallet", "nep5", "info", + e.Run(t, "neo-go", "wallet", "nep17", "info", "--wallet", walletPath) checkGASInfo(t) _, err := e.Out.ReadString('\n') diff --git a/cli/wallet/nep5.go b/cli/wallet/nep17.go similarity index 91% rename from cli/wallet/nep5.go rename to cli/wallet/nep17.go index 35f228712..27eab4ee5 100644 --- a/cli/wallet/nep5.go +++ b/cli/wallet/nep17.go @@ -26,7 +26,7 @@ var ( } ) -func newNEP5Commands() []cli.Command { +func newNEP17Commands() []cli.Command { balanceFlags := []cli.Flag{ walletPathFlag, tokenFlag, @@ -69,21 +69,21 @@ func newNEP5Commands() []cli.Command { Name: "balance", Usage: "get address balance", UsageText: "balance --wallet --rpc-endpoint [--timeout