diff --git a/cli/testdata/verify.manifest.json b/cli/testdata/verify.manifest.json index 518bcd896..103a744a8 100755 --- a/cli/testdata/verify.manifest.json +++ b/cli/testdata/verify.manifest.json @@ -1 +1 @@ -{"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 +{"name":"verify","abi":{"methods":[{"name":"verify","offset":0,"parameters":[],"returntype":"Boolean","safe":false},{"name":"onPayment","offset":5,"parameters":[{"name":"from","type":"ByteArray"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false}],"events":[{"name":"Hello world!","parameters":[{"name":"args","type":"Array"}]}]},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null} \ No newline at end of file diff --git a/cli/testdata/verify.nef b/cli/testdata/verify.nef index 5bb3c8bbe..5023c4548 100755 Binary files a/cli/testdata/verify.nef and b/cli/testdata/verify.nef differ diff --git a/pkg/core/interop/context.go b/pkg/core/interop/context.go index d82ff2748..02ac19bfb 100644 --- a/pkg/core/interop/context.go +++ b/pkg/core/interop/context.go @@ -117,9 +117,8 @@ func NewContractMD(name string, id int32) *ContractMD { // NEF is now stored in contract state and affects state dump. // Therefore values are taken from C# node. - c.NEF.Header.Compiler = "ScriptBuilder" + c.NEF.Header.Compiler = "neo-core-v3.0" c.NEF.Header.Magic = nef.Magic - c.NEF.Header.Version = "3.0" c.NEF.Script, c.Hash = state.CreateNativeContractHash(id) c.NEF.Checksum = c.NEF.CalculateChecksum() c.Manifest = *manifest.DefaultManifest(name) diff --git a/pkg/core/state/contract_test.go b/pkg/core/state/contract_test.go index 9ea4c627a..5d4c224f1 100644 --- a/pkg/core/state/contract_test.go +++ b/pkg/core/state/contract_test.go @@ -41,9 +41,9 @@ func TestEncodeDecodeContractState(t *testing.T) { NEF: nef.File{ Header: nef.Header{ Magic: nef.Magic, - Compiler: "neo-go.test", - Version: "test", + Compiler: "neo-go.test-test", }, + Tokens: []nef.MethodToken{}, Script: script, Checksum: 0, }, diff --git a/pkg/io/binaryReader.go b/pkg/io/binaryReader.go index b8c935c80..6915f5109 100644 --- a/pkg/io/binaryReader.go +++ b/pkg/io/binaryReader.go @@ -193,7 +193,7 @@ func (r *BinReader) ReadBytes(buf []byte) { } // ReadString calls ReadVarBytes and casts the results as a string. -func (r *BinReader) ReadString() string { - b := r.ReadVarBytes() +func (r *BinReader) ReadString(maxSize ...int) string { + b := r.ReadVarBytes(maxSize...) return string(b) } diff --git a/pkg/rpc/client/rpc_test.go b/pkg/rpc/client/rpc_test.go index aa2b4bca4..7e5a713d8 100644 --- a/pkg/rpc/client/rpc_test.go +++ b/pkg/rpc/client/rpc_test.go @@ -330,7 +330,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ } return c.GetContractStateByHash(hash) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"nef":{"magic":860243278,"compiler":"neo-go","version":"3.0","script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","checksum":749050685},"manifest":{"name":"Test","abi":{"methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"nef":{"magic":860243278,"compiler":"neo-go-3.0","script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","checksum":2512077441},"manifest":{"name":"Test","abi":{"methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`, result: func(c *Client) interface{} { script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==") if err != nil { @@ -351,7 +351,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ invoke: func(c *Client) (interface{}, error) { return c.GetContractStateByAddressOrName("NWiu5oejTu925aeL9Hc1LX8SvaJhE23h15") }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"nef":{"magic":860243278,"compiler":"neo-go","version":"3.0","script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","checksum":749050685},"manifest":{"name":"Test","abi":{"methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"nef":{"magic":860243278,"compiler":"neo-go-3.0","script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","checksum":2512077441},"manifest":{"name":"Test","abi":{"methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`, result: func(c *Client) interface{} { script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==") if err != nil { @@ -372,7 +372,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ invoke: func(c *Client) (interface{}, error) { return c.GetContractStateByID(0) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"nef":{"magic":860243278,"compiler":"neo-go","version":"3.0","script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","checksum":749050685},"manifest":{"name":"Test","abi":{"methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"nef":{"magic":860243278,"compiler":"neo-go-3.0","script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","checksum":2512077441},"manifest":{"name":"Test","abi":{"methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`, result: func(c *Client) interface{} { script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==") if err != nil { @@ -1632,8 +1632,7 @@ func TestUninitedClient(t *testing.T) { func newTestNEF(script []byte) nef.File { var ne nef.File ne.Header.Magic = nef.Magic - ne.Header.Version = "3.0" - ne.Header.Compiler = "neo-go" + ne.Header.Compiler = "neo-go-3.0" ne.Script = script ne.Checksum = ne.CalculateChecksum() return ne diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index 41fc7282a..259321b3f 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -57,7 +57,7 @@ type rpcTestCase struct { } const testContractHash = "0b3bc97e94ed99e32dda46c9ecd2d3626979af06" -const deploymentTxHash = "4288bb6ad12426a9e34f6af4c050bc291798a46958443d614f457a9a12f087c2" +const deploymentTxHash = "e3a67acac29014dc8c24773752ac4535a0f020486749ec5c907234fc9328246c" const genesisBlockHash = "0542f4350c6e236d0509bcd98188b0034bfbecc1a0c7fcdb8e4295310d468b70" const verifyContractHash = "d2da8ee8c0bf6c5bf3dda1ef671dbf5fef7226e9" @@ -1408,7 +1408,7 @@ func checkNep17Balances(t *testing.T, e *executor, acc interface{}) { }, { Asset: e.chain.UtilityTokenHash(), - Amount: "80006675650", + Amount: "80006665650", LastUpdated: 7, }}, Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(), diff --git a/pkg/rpc/server/testdata/testblocks.acc b/pkg/rpc/server/testdata/testblocks.acc index f98ff66b7..f3e5350c9 100644 Binary files a/pkg/rpc/server/testdata/testblocks.acc and b/pkg/rpc/server/testdata/testblocks.acc differ diff --git a/pkg/smartcontract/nef/method_token.go b/pkg/smartcontract/nef/method_token.go new file mode 100644 index 000000000..48aeacd89 --- /dev/null +++ b/pkg/smartcontract/nef/method_token.go @@ -0,0 +1,57 @@ +package nef + +import ( + "errors" + "strings" + + "github.com/nspcc-dev/neo-go/pkg/io" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" + "github.com/nspcc-dev/neo-go/pkg/util" +) + +// maxMethodLength is the maximum length of method. +const maxMethodLength = 32 + +var ( + errInvalidMethodName = errors.New("method name should't start with '_'") + errInvalidCallFlag = errors.New("invalid call flag") +) + +// MethodToken is contract method description. +type MethodToken struct { + // Hash is contract hash. + Hash util.Uint160 `json:"hash"` + // Method is method name. + Method string `json:"method"` + // ParamCount is method parameter count. + ParamCount uint16 `json:"paramcount"` + // HasReturn is true if method returns value. + HasReturn bool `json:"hasreturnvalue"` + // CallFlag is a set of call flags the method will be called with. + CallFlag callflag.CallFlag `json:"callflags"` +} + +// EncodeBinary implements io.Serializable. +func (t *MethodToken) EncodeBinary(w *io.BinWriter) { + w.WriteBytes(t.Hash[:]) + w.WriteString(t.Method) + w.WriteU16LE(t.ParamCount) + w.WriteBool(t.HasReturn) + w.WriteB(byte(t.CallFlag)) +} + +// DecodeBinary implements io.Serializable. +func (t *MethodToken) DecodeBinary(r *io.BinReader) { + r.ReadBytes(t.Hash[:]) + t.Method = r.ReadString(maxMethodLength) + if r.Err == nil && strings.HasPrefix(t.Method, "_") { + r.Err = errInvalidMethodName + return + } + t.ParamCount = r.ReadU16LE() + t.HasReturn = r.ReadBool() + t.CallFlag = callflag.CallFlag(r.ReadB()) + if r.Err == nil && t.CallFlag&^callflag.All != 0 { + r.Err = errInvalidCallFlag + } +} diff --git a/pkg/smartcontract/nef/method_token_test.go b/pkg/smartcontract/nef/method_token_test.go new file mode 100644 index 000000000..05072723d --- /dev/null +++ b/pkg/smartcontract/nef/method_token_test.go @@ -0,0 +1,50 @@ +package nef + +import ( + "errors" + "strings" + "testing" + + "github.com/nspcc-dev/neo-go/internal/random" + "github.com/nspcc-dev/neo-go/internal/testserdes" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" + "github.com/stretchr/testify/require" +) + +func TestMethodToken_Serializable(t *testing.T) { + getToken := func() *MethodToken { + return &MethodToken{ + Hash: random.Uint160(), + Method: "MethodName", + ParamCount: 2, + HasReturn: true, + CallFlag: callflag.ReadStates, + } + } + t.Run("good", func(t *testing.T) { + testserdes.EncodeDecodeBinary(t, getToken(), new(MethodToken)) + }) + t.Run("too long name", func(t *testing.T) { + tok := getToken() + tok.Method = strings.Repeat("s", maxMethodLength+1) + data, err := testserdes.EncodeBinary(tok) + require.NoError(t, err) + require.Error(t, testserdes.DecodeBinary(data, new(MethodToken))) + }) + t.Run("start with '_'", func(t *testing.T) { + tok := getToken() + tok.Method = "_method" + data, err := testserdes.EncodeBinary(tok) + require.NoError(t, err) + err = testserdes.DecodeBinary(data, new(MethodToken)) + require.True(t, errors.Is(err, errInvalidMethodName)) + }) + t.Run("invalid call flag", func(t *testing.T) { + tok := getToken() + tok.CallFlag = ^callflag.All + data, err := testserdes.EncodeBinary(tok) + require.NoError(t, err) + err = testserdes.DecodeBinary(data, new(MethodToken)) + require.True(t, errors.Is(err, errInvalidCallFlag)) + }) +} diff --git a/pkg/smartcontract/nef/nef.go b/pkg/smartcontract/nef/nef.go index 74476d0ab..71e470dc2 100644 --- a/pkg/smartcontract/nef/nef.go +++ b/pkg/smartcontract/nef/nef.go @@ -17,9 +17,11 @@ import ( // | Field | Length | Comment | // +------------+-----------+------------------------------------------------------------+ // | Magic | 4 bytes | Magic header | -// | Compiler | 32 bytes | Compiler used | -// | Version | 32 bytes | Compiler version | +// | Compiler | 64 bytes | Compiler used and it's version | // +------------+-----------+------------------------------------------------------------+ +// | Reserved | 2-bytes | Reserved for extensions. Must be 0. | +// | Tokens | Var array | List of method tokens | +// | Reserved | 2-bytes | Reserved for extensions. Must be 0. | // | Script | Var bytes | Var bytes for the payload | // +------------+-----------+------------------------------------------------------------+ // | Checksum | 4 bytes | First four bytes of double SHA256 hash of the header | @@ -30,22 +32,22 @@ const ( Magic uint32 = 0x3346454E // MaxScriptLength is the maximum allowed contract script length. MaxScriptLength = 512 * 1024 - // compilerFieldSize is the length of `Compiler` and `Version` File header fields in bytes. - compilerFieldSize = 32 + // compilerFieldSize is the length of `Compiler` File header field in bytes. + compilerFieldSize = 64 ) // File represents compiled contract file structure according to the NEF3 standard. type File struct { Header - Script []byte `json:"script"` - Checksum uint32 `json:"checksum"` + Tokens []MethodToken `json:"tokens"` + Script []byte `json:"script"` + Checksum uint32 `json:"checksum"` } // Header represents File header. type Header struct { Magic uint32 `json:"magic"` Compiler string `json:"compiler"` - Version string `json:"version"` } // NewFile returns new NEF3 file with script specified. @@ -53,13 +55,13 @@ func NewFile(script []byte) (*File, error) { file := &File{ Header: Header{ Magic: Magic, - Compiler: "neo-go", - Version: config.Version, + Compiler: "neo-go-" + config.Version, }, + Tokens: []MethodToken{}, Script: script, } - if len(config.Version) > compilerFieldSize { - return nil, errors.New("too long version") + if len(file.Compiler) > compilerFieldSize { + return nil, errors.New("too long compiler field") } file.Checksum = file.CalculateChecksum() return file, nil @@ -75,11 +77,6 @@ func (h *Header) EncodeBinary(w *io.BinWriter) { var b = make([]byte, compilerFieldSize) copy(b, []byte(h.Compiler)) w.WriteBytes(b) - for i := range b { - b[i] = 0 - } - copy(b, []byte(h.Version)) - w.WriteBytes(b) } // DecodeBinary implements io.Serializable interface. @@ -95,12 +92,6 @@ func (h *Header) DecodeBinary(r *io.BinReader) { return r == 0 }) h.Compiler = string(buf) - buf = buf[:compilerFieldSize] - r.ReadBytes(buf) - buf = bytes.TrimRightFunc(buf, func(r rune) bool { - return r == 0 - }) - h.Version = string(buf) } // CalculateChecksum returns first 4 bytes of double-SHA256(Header) converted to uint32. @@ -115,21 +106,37 @@ func (n *File) CalculateChecksum() uint32 { // EncodeBinary implements io.Serializable interface. func (n *File) EncodeBinary(w *io.BinWriter) { n.Header.EncodeBinary(w) + w.WriteU16LE(0) + w.WriteArray(n.Tokens) + w.WriteU16LE(0) w.WriteVarBytes(n.Script) w.WriteU32LE(n.Checksum) } +var errInvalidReserved = errors.New("reserved bytes must be 0") + // DecodeBinary implements io.Serializable interface. func (n *File) DecodeBinary(r *io.BinReader) { n.Header.DecodeBinary(r) + reserved := r.ReadU16LE() + if r.Err == nil && reserved != 0 { + r.Err = errInvalidReserved + return + } + r.ReadArray(&n.Tokens) + reserved = r.ReadU16LE() + if r.Err == nil && reserved != 0 { + r.Err = errInvalidReserved + return + } n.Script = r.ReadVarBytes(MaxScriptLength) - if len(n.Script) == 0 { + if r.Err == nil && len(n.Script) == 0 { r.Err = errors.New("empty script") return } n.Checksum = r.ReadU32LE() checksum := n.CalculateChecksum() - if checksum != n.Checksum { + if r.Err == nil && checksum != n.Checksum { r.Err = errors.New("checksum verification failure") return } diff --git a/pkg/smartcontract/nef/nef_test.go b/pkg/smartcontract/nef/nef_test.go index c0054e461..8c52bae2c 100644 --- a/pkg/smartcontract/nef/nef_test.go +++ b/pkg/smartcontract/nef/nef_test.go @@ -3,10 +3,15 @@ package nef import ( "encoding/base64" "encoding/json" + "errors" "strconv" "testing" + "github.com/nspcc-dev/neo-go/internal/random" "github.com/nspcc-dev/neo-go/internal/testserdes" + "github.com/nspcc-dev/neo-go/pkg/io" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" + "github.com/nspcc-dev/neo-go/pkg/util" "github.com/stretchr/testify/require" ) @@ -15,9 +20,15 @@ func TestEncodeDecodeBinary(t *testing.T) { expected := &File{ Header: Header{ Magic: Magic, - Compiler: "the best compiler ever", - Version: "1.2.3.4", + Compiler: "best compiler version 1", }, + Tokens: []MethodToken{{ + Hash: random.Uint160(), + Method: "method", + ParamCount: 3, + HasReturn: true, + CallFlag: callflag.WriteStates, + }}, Script: script, } @@ -44,13 +55,37 @@ func TestEncodeDecodeBinary(t *testing.T) { expected.Checksum = expected.CalculateChecksum() checkDecodeError(t, expected) }) + t.Run("invalid tokens list", func(t *testing.T) { + expected.Script = script + expected.Tokens[0].Method = "_reserved" + expected.Checksum = expected.CalculateChecksum() + checkDecodeError(t, expected) + }) t.Run("positive", func(t *testing.T) { expected.Script = script + expected.Tokens[0].Method = "method" expected.Checksum = expected.CalculateChecksum() expected.Header.Magic = Magic testserdes.EncodeDecodeBinary(t, expected, &File{}) }) + t.Run("invalid reserved bytes", func(t *testing.T) { + expected.Script = script + expected.Tokens = expected.Tokens[:0] + expected.Checksum = expected.CalculateChecksum() + bytes, err := testserdes.EncodeBinary(expected) + require.NoError(t, err) + + sz := io.GetVarSize(&expected.Header) + bytes[sz] = 1 + err = testserdes.DecodeBinary(bytes, new(File)) + require.True(t, errors.Is(err, errInvalidReserved), "got: %v", err) + + bytes[sz] = 0 + bytes[sz+3] = 1 + err = testserdes.DecodeBinary(bytes, new(File)) + require.True(t, errors.Is(err, errInvalidReserved), "got: %v", err) + }) } func checkDecodeError(t *testing.T, expected *File) { @@ -64,9 +99,15 @@ func TestBytesFromBytes(t *testing.T) { expected := File{ Header: Header{ Magic: Magic, - Compiler: "the best compiler ever", - Version: "1.2.3.4", + Compiler: "best compiler version 1", }, + Tokens: []MethodToken{{ + Hash: random.Uint160(), + Method: "someMethod", + ParamCount: 3, + HasReturn: true, + CallFlag: callflag.WriteStates, + }}, Script: script, } expected.Checksum = expected.CalculateChecksum() @@ -82,9 +123,15 @@ func TestMarshalUnmarshalJSON(t *testing.T) { expected := &File{ Header: Header{ Magic: Magic, - Compiler: "test.compiler", - Version: "test.ver", + Compiler: "test.compiler-test.ver", }, + Tokens: []MethodToken{{ + Hash: util.Uint160{0x12, 0x34, 0x56, 0x78, 0x91, 0x00}, + Method: "someMethod", + ParamCount: 3, + HasReturn: true, + CallFlag: callflag.WriteStates, + }}, Script: []byte{1, 2, 3, 4}, } expected.Checksum = expected.CalculateChecksum() @@ -93,8 +140,16 @@ func TestMarshalUnmarshalJSON(t *testing.T) { require.NoError(t, err) require.JSONEq(t, `{ "magic":`+strconv.FormatUint(uint64(Magic), 10)+`, - "compiler": "test.compiler", - "version": "test.ver", + "compiler": "test.compiler-test.ver", + "tokens": [ + { + "hash": "0x`+expected.Tokens[0].Hash.StringLE()+`", + "method": "someMethod", + "paramcount": 3, + "hasreturnvalue": true, + "callflags": `+strconv.FormatInt(int64(expected.Tokens[0].CallFlag), 10)+` + } + ], "script": "`+base64.StdEncoding.EncodeToString(expected.Script)+`", "checksum":`+strconv.FormatUint(uint64(expected.Checksum), 10)+`}`, string(data))