nspcc-dev / neo-go

Go Node and SDK for the Neo blockchain
MIT License
125 stars 79 forks source link

Ensure star type assertion is handled properly #3248

Open AnnaShaleva opened 1 year ago

AnnaShaleva commented 1 year ago

Is your feature request related to a problem? Please describe.

Suppose we have a structure declared in the contract:

type (
    UserKey struct {
        Address interop.Hash160
        Data    []byte
        Role    int
    }
)

And suppose we have the following method:

func GetUserKey(ctx storage.Context, idKey []byte) *UserKey {
    data := storage.Get(ctx, idKey)
    if data != nil {
        return std.Deserialize(data.([]byte)).(*UserKey)
    }

    return nil
}

The result of compilation is invalid script:

    compile.go:55: 
            Error Trace:    /home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/neotest/compile.go:55
                                        /home/anna/Documents/GitProjects/nspcc-dev/console/internal/contract/usermanagement/usermanagement_contract_test.go:17
                                        /home/anna/Documents/GitProjects/nspcc-dev/console/internal/contract/usermanagement/usermanagement_contract_test.go:24
            Error:          Received unexpected error:
                            using type ANY is incorrect at offset 275

The wrong line is the conversion of structure got after std.Deserialize to Any (which is the pointer to UserKey).

Describe the solution you'd like

The desired result is to convert the structure got after std.Deserialize directly to the UserKey structure if it's not nil. The case is that this code is very similar to the one that we have in our interop package: https://github.com/nspcc-dev/neo-go/blob/9a270ae30cb889ecbc346efc2efa1d1b6c408abd/pkg/interop/native/ledger/ledger.go#L42-L44 However, the interop API works fine.

roman-khimov commented 1 year ago

Interops are inlined and IIRC there is some special code to handle interop data types, but in general your example should work, so it's just a bug in pointer handling.

roman-khimov commented 2 months ago

The workaround from https://github.com/nspcc-dev/neo-go/issues/3580#issuecomment-2341916070 doesn't really work, btw (nothing is copied, NULLs are left in the struct). Field-by-field assignments do work.