Merge pull request #1672 from nspcc-dev/fix/nef

Fix NEF serialization
This commit is contained in:
Roman Khimov 2021-01-19 15:57:48 +03:00 committed by GitHub
commit fbbcb16fa1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 213 additions and 46 deletions

View file

@ -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}
{"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}

Binary file not shown.

View file

@ -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)

View file

@ -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,
},

View file

@ -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)
}

View file

@ -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

View file

@ -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(),

Binary file not shown.

View file

@ -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
}
}

View file

@ -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))
})
}

View file

@ -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
}

View file

@ -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))