Merge pull request #1665 from nspcc-dev/nefstate

Store NEF in contract state
This commit is contained in:
Roman Khimov 2021-01-14 10:14:38 +03:00 committed by GitHub
commit 36b5751262
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 172 additions and 78 deletions

View file

@ -424,7 +424,7 @@ func importDeployed(ctx *cli.Context) error {
return cli.NewExitError("contract has no `verify` method", 1) return cli.NewExitError("contract has no `verify` method", 1)
} }
acc.Address = address.Uint160ToString(cs.Hash) acc.Address = address.Uint160ToString(cs.Hash)
acc.Contract.Script = cs.Script acc.Contract.Script = cs.NEF.Script
acc.Contract.Parameters = acc.Contract.Parameters[:0] acc.Contract.Parameters = acc.Contract.Parameters[:0]
for _, p := range md.Parameters { for _, p := range md.Parameters {
acc.Contract.Parameters = append(acc.Contract.Parameters, wallet.ContractParam{ acc.Contract.Parameters = append(acc.Contract.Parameters, wallet.ContractParam{

View file

@ -18,6 +18,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
cinterop "github.com/nspcc-dev/neo-go/pkg/interop" cinterop "github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
@ -162,15 +163,19 @@ func TestAppCall(t *testing.T) {
ih := hash.Hash160(inner) ih := hash.Hash160(inner)
var contractGetter = func(_ dao.DAO, h util.Uint160) (*state.Contract, error) { var contractGetter = func(_ dao.DAO, h util.Uint160) (*state.Contract, error) {
if h.Equals(ih) { if h.Equals(ih) {
innerNef, err := nef.NewFile(inner)
require.NoError(t, err)
return &state.Contract{ return &state.Contract{
Hash: ih, Hash: ih,
Script: inner, NEF: *innerNef,
Manifest: *m, Manifest: *m,
}, nil }, nil
} else if h.Equals(barH) { } else if h.Equals(barH) {
barNef, err := nef.NewFile(barCtr)
require.NoError(t, err)
return &state.Contract{ return &state.Contract{
Hash: barH, Hash: barH,
Script: barCtr, NEF: *barNef,
Manifest: *mBar, Manifest: *mBar,
}, nil }, nil
} }

View file

@ -1670,7 +1670,7 @@ func (bc *Blockchain) initVerificationVM(ic *interop.Context, hash util.Uint160,
return ErrInvalidVerificationContract return ErrInvalidVerificationContract
} }
initMD := cs.Manifest.ABI.GetMethod(manifest.MethodInit) initMD := cs.Manifest.ABI.GetMethod(manifest.MethodInit)
v.LoadScriptWithHash(cs.Script, hash, smartcontract.ReadStates) v.LoadScriptWithHash(cs.NEF.Script, hash, smartcontract.ReadStates)
v.Jump(v.Context(), md.Offset) v.Jump(v.Context(), md.Offset)
if cs.ID <= 0 { if cs.ID <= 0 {

View file

@ -418,7 +418,7 @@ func addNetworkFee(bc *Blockchain, tx *transaction.Transaction, sender *wallet.A
for _, cosigner := range tx.Signers { for _, cosigner := range tx.Signers {
contract := bc.GetContractState(cosigner.Account) contract := bc.GetContractState(cosigner.Account)
if contract != nil { if contract != nil {
netFee, sizeDelta = fee.Calculate(bc.GetBaseExecFee(), contract.Script) netFee, sizeDelta = fee.Calculate(bc.GetBaseExecFee(), contract.NEF.Script)
tx.NetworkFee += netFee tx.NetworkFee += netFee
size += sizeDelta size += sizeDelta
} }

View file

@ -13,6 +13,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto" "github.com/nspcc-dev/neo-go/pkg/crypto"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
@ -103,7 +104,7 @@ type ContractMD struct {
Manifest manifest.Manifest Manifest manifest.Manifest
Name string Name string
ContractID int32 ContractID int32
Script []byte NEF nef.File
Hash util.Uint160 Hash util.Uint160
Methods map[string]MethodAndPrice Methods map[string]MethodAndPrice
} }
@ -115,7 +116,13 @@ func NewContractMD(name string) *ContractMD {
Methods: make(map[string]MethodAndPrice), Methods: make(map[string]MethodAndPrice),
} }
c.Script, c.Hash = state.CreateNativeContractHash(c.Name) // 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.Magic = nef.Magic
c.NEF.Header.Version = "3.0"
c.NEF.Script, c.Hash = state.CreateNativeContractHash(c.Name)
c.NEF.Checksum = c.NEF.CalculateChecksum()
c.Manifest = *manifest.DefaultManifest(name) c.Manifest = *manifest.DefaultManifest(name)
return c return c

View file

@ -82,7 +82,7 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
} }
ic.VM.Invocations[cs.Hash]++ ic.VM.Invocations[cs.Hash]++
ic.VM.LoadScriptWithCallingHash(caller, cs.Script, cs.Hash, ic.VM.Context().GetCallFlags()&f) ic.VM.LoadScriptWithCallingHash(caller, cs.NEF.Script, cs.Hash, ic.VM.Context().GetCallFlags()&f)
var isNative bool var isNative bool
for i := range ic.Natives { for i := range ic.Natives {
if ic.Natives[i].Metadata().Hash.Equals(cs.Hash) { if ic.Natives[i].Metadata().Hash.Equals(cs.Hash) {

View file

@ -14,6 +14,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
@ -160,8 +161,10 @@ func createVMAndPushTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interop
func createVMAndContractState(t *testing.T) (*vm.VM, *state.Contract, *interop.Context, *Blockchain) { func createVMAndContractState(t *testing.T) (*vm.VM, *state.Contract, *interop.Context, *Blockchain) {
script := []byte("testscript") script := []byte("testscript")
m := manifest.NewManifest("Test") m := manifest.NewManifest("Test")
ne, err := nef.NewFile(script)
require.NoError(t, err)
contractState := &state.Contract{ contractState := &state.Contract{
Script: script, NEF: *ne,
Hash: hash.Hash160(script), Hash: hash.Hash160(script),
Manifest: *m, Manifest: *m,
ID: 123, ID: 123,

View file

@ -338,7 +338,7 @@ func contractIsStandard(ic *interop.Context) error {
var result bool var result bool
cs, _ := ic.GetContract(u) cs, _ := ic.GetContract(u)
if cs != nil { if cs != nil {
result = vm.IsStandardContract(cs.Script) result = vm.IsStandardContract(cs.NEF.Script)
} else { } else {
if tx, ok := ic.Container.(*transaction.Transaction); ok { if tx, ok := ic.Container.(*transaction.Transaction); ok {
for _, witness := range tx.Scripts { for _, witness := range tx.Scripts {

View file

@ -21,6 +21,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "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/emit"
@ -226,7 +227,9 @@ func TestContractIsStandard(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
pub := priv.PublicKey() pub := priv.PublicKey()
err = chain.contracts.Management.PutContractState(ic.DAO, &state.Contract{ID: 42, Hash: pub.GetScriptHash(), Script: pub.GetVerificationScript()}) ne, err := nef.NewFile(pub.GetVerificationScript())
require.NoError(t, err)
err = chain.contracts.Management.PutContractState(ic.DAO, &state.Contract{ID: 42, Hash: pub.GetScriptHash(), NEF: *ne})
require.NoError(t, err) require.NoError(t, err)
v.Estack().PushVal(pub.GetScriptHash().BytesBE()) v.Estack().PushVal(pub.GetScriptHash().BytesBE())
@ -235,7 +238,9 @@ func TestContractIsStandard(t *testing.T) {
}) })
t.Run("contract stored, false", func(t *testing.T) { t.Run("contract stored, false", func(t *testing.T) {
script := []byte{byte(opcode.PUSHT)} script := []byte{byte(opcode.PUSHT)}
require.NoError(t, chain.contracts.Management.PutContractState(ic.DAO, &state.Contract{ID: 24, Hash: hash.Hash160(script), Script: script})) ne, err := nef.NewFile(script)
require.NoError(t, err)
require.NoError(t, chain.contracts.Management.PutContractState(ic.DAO, &state.Contract{ID: 24, Hash: hash.Hash160(script), NEF: *ne}))
v.Estack().PushVal(crypto.Hash160(script).BytesBE()) v.Estack().PushVal(crypto.Hash160(script).BytesBE())
require.NoError(t, contractIsStandard(ic)) require.NoError(t, contractIsStandard(ic))
@ -343,7 +348,7 @@ func TestStoragePut(t *testing.T) {
initVM := func(t *testing.T, key, value []byte, gas int64) { initVM := func(t *testing.T, key, value []byte, gas int64) {
v := ic.SpawnVM() v := ic.SpawnVM()
v.LoadScript(cs.Script) v.LoadScript(cs.NEF.Script)
v.GasLimit = gas v.GasLimit = gas
v.Estack().PushVal(value) v.Estack().PushVal(value)
v.Estack().PushVal(key) v.Estack().PushVal(key)
@ -392,7 +397,7 @@ func TestStoragePut(t *testing.T) {
}) })
t.Run("item exists and is const", func(t *testing.T) { t.Run("item exists and is const", func(t *testing.T) {
v := ic.SpawnVM() v := ic.SpawnVM()
v.LoadScript(cs.Script) v.LoadScript(cs.NEF.Script)
v.GasLimit = -1 v.GasLimit = -1
v.Estack().PushVal(1) v.Estack().PushVal(1)
v.Estack().PushVal("value") v.Estack().PushVal("value")
@ -413,7 +418,7 @@ func TestStorageDelete(t *testing.T) {
defer bc.Close() defer bc.Close()
require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, cs)) require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, cs))
v.LoadScriptWithHash(cs.Script, cs.Hash, smartcontract.All) v.LoadScriptWithHash(cs.NEF.Script, cs.Hash, smartcontract.All)
put := func(key, value string, flag int) { put := func(key, value string, flag int) {
v.Estack().PushVal(flag) v.Estack().PushVal(flag)
v.Estack().PushVal(value) v.Estack().PushVal(value)
@ -615,11 +620,15 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
}, },
} }
cs := &state.Contract{ cs := &state.Contract{
Script: script,
Hash: h, Hash: h,
Manifest: *m, Manifest: *m,
ID: 42, ID: 42,
} }
ne, err := nef.NewFile(script)
if err != nil {
panic(err)
}
cs.NEF = *ne
currScript := []byte{byte(opcode.RET)} currScript := []byte{byte(opcode.RET)}
m = manifest.NewManifest("TestAux") m = manifest.NewManifest("TestAux")
@ -631,9 +640,13 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
perm.Methods.Add("justReturn") perm.Methods.Add("justReturn")
perm.Methods.Add("getValue") perm.Methods.Add("getValue")
m.Permissions = append(m.Permissions, *perm) m.Permissions = append(m.Permissions, *perm)
ne, err = nef.NewFile(currScript)
if err != nil {
panic(err)
}
return cs, &state.Contract{ return cs, &state.Contract{
Script: currScript, NEF: *ne,
Hash: hash.Hash160(currScript), Hash: hash.Hash160(currScript),
Manifest: *m, Manifest: *m,
ID: 123, ID: 123,
@ -666,8 +679,8 @@ func TestContractCall(t *testing.T) {
require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, cs)) require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, cs))
require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, currCs)) require.NoError(t, bc.contracts.Management.PutContractState(ic.DAO, currCs))
currScript := currCs.Script currScript := currCs.NEF.Script
h := hash.Hash160(cs.Script) h := hash.Hash160(cs.NEF.Script)
addArgs := stackitem.NewArray([]stackitem.Item{stackitem.Make(1), stackitem.Make(2)}) addArgs := stackitem.NewArray([]stackitem.Item{stackitem.Make(1), stackitem.Make(2)})
t.Run("Good", func(t *testing.T) { t.Run("Good", func(t *testing.T) {
@ -823,7 +836,7 @@ func TestMethodCallback(t *testing.T) {
t.Run("Invalid", func(t *testing.T) { t.Run("Invalid", func(t *testing.T) {
runInvalid := func(args ...interface{}) func(t *testing.T) { runInvalid := func(args ...interface{}) func(t *testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
loadScript(ic, currCs.Script, 42) loadScript(ic, currCs.NEF.Script, 42)
for i := range args { for i := range args {
ic.VM.Estack().PushVal(args[i]) ic.VM.Estack().PushVal(args[i])
} }
@ -836,7 +849,7 @@ func TestMethodCallback(t *testing.T) {
t.Run("DisallowedMethod", runInvalid("ret7", rawHash)) t.Run("DisallowedMethod", runInvalid("ret7", rawHash))
t.Run("Initialize", runInvalid("_initialize", rawHash)) t.Run("Initialize", runInvalid("_initialize", rawHash))
t.Run("NotEnoughArguments", func(t *testing.T) { t.Run("NotEnoughArguments", func(t *testing.T) {
loadScript(ic, currCs.Script, 42, "add", rawHash) loadScript(ic, currCs.NEF.Script, 42, "add", rawHash)
require.NoError(t, callback.CreateFromMethod(ic)) require.NoError(t, callback.CreateFromMethod(ic))
ic.VM.Estack().InsertAt(vm.NewElement(stackitem.NewArray([]stackitem.Item{stackitem.Make(1)})), 1) ic.VM.Estack().InsertAt(vm.NewElement(stackitem.NewArray([]stackitem.Item{stackitem.Make(1)})), 1)
@ -844,7 +857,7 @@ func TestMethodCallback(t *testing.T) {
}) })
t.Run("CallIsNotAllowed", func(t *testing.T) { t.Run("CallIsNotAllowed", func(t *testing.T) {
ic.SpawnVM() ic.SpawnVM()
ic.VM.Load(currCs.Script) ic.VM.Load(currCs.NEF.Script)
ic.VM.Estack().PushVal("add") ic.VM.Estack().PushVal("add")
ic.VM.Estack().PushVal(rawHash) ic.VM.Estack().PushVal(rawHash)
require.NoError(t, callback.CreateFromMethod(ic)) require.NoError(t, callback.CreateFromMethod(ic))
@ -856,7 +869,7 @@ func TestMethodCallback(t *testing.T) {
}) })
t.Run("Good", func(t *testing.T) { t.Run("Good", func(t *testing.T) {
loadScript(ic, currCs.Script, 42, "add", rawHash) loadScript(ic, currCs.NEF.Script, 42, "add", rawHash)
require.NoError(t, callback.CreateFromMethod(ic)) require.NoError(t, callback.CreateFromMethod(ic))
args := stackitem.NewArray([]stackitem.Item{stackitem.Make(1), stackitem.Make(5)}) args := stackitem.NewArray([]stackitem.Item{stackitem.Make(1), stackitem.Make(5)})
@ -1074,10 +1087,12 @@ func TestRuntimeCheckWitness(t *testing.T) {
} }
contractScript := []byte{byte(opcode.PUSH1), byte(opcode.RET)} contractScript := []byte{byte(opcode.PUSH1), byte(opcode.RET)}
contractScriptHash := hash.Hash160(contractScript) contractScriptHash := hash.Hash160(contractScript)
ne, err := nef.NewFile(contractScript)
require.NoError(t, err)
contractState := &state.Contract{ contractState := &state.Contract{
ID: 15, ID: 15,
Hash: contractScriptHash, Hash: contractScriptHash,
Script: contractScript, NEF: *ne,
Manifest: manifest.Manifest{ Manifest: manifest.Manifest{
Groups: []manifest.Group{{PublicKey: pk.PublicKey()}}, Groups: []manifest.Group{{PublicKey: pk.PublicKey()}},
}, },

View file

@ -252,7 +252,7 @@ func (m *Management) Deploy(d dao.DAO, sender util.Uint160, neff *nef.File, mani
newcontract := &state.Contract{ newcontract := &state.Contract{
ID: id, ID: id,
Hash: h, Hash: h,
Script: neff.Script, NEF: *neff,
Manifest: *manif, Manifest: *manif,
} }
err = m.PutContractState(d, newcontract) err = m.PutContractState(d, newcontract)
@ -292,7 +292,7 @@ func (m *Management) Update(d dao.DAO, hash util.Uint160, neff *nef.File, manif
// if NEF was provided, update the contract script // if NEF was provided, update the contract script
if neff != nil { if neff != nil {
m.markUpdated(hash) m.markUpdated(hash)
contract.Script = neff.Script contract.NEF = *neff
} }
// if manifest was provided, update the contract manifest // if manifest was provided, update the contract manifest
if manif != nil { if manif != nil {
@ -415,7 +415,7 @@ func (m *Management) OnPersist(ic *interop.Context) error {
cs := &state.Contract{ cs := &state.Contract{
ID: md.ContractID, ID: md.ContractID,
Hash: md.Hash, Hash: md.Hash,
Script: md.Script, NEF: md.NEF,
Manifest: md.Manifest, Manifest: md.Manifest,
} }
err := m.PutContractState(ic.DAO, cs) err := m.PutContractState(ic.DAO, cs)

View file

@ -30,7 +30,7 @@ func TestDeployGetUpdateDestroyContract(t *testing.T) {
require.Equal(t, int32(1), contract.ID) require.Equal(t, int32(1), contract.ID)
require.Equal(t, uint16(0), contract.UpdateCounter) require.Equal(t, uint16(0), contract.UpdateCounter)
require.Equal(t, h, contract.Hash) require.Equal(t, h, contract.Hash)
require.Equal(t, script, contract.Script) require.Equal(t, ne, &contract.NEF)
require.Equal(t, *manif, contract.Manifest) require.Equal(t, *manif, contract.Manifest)
// Double deploy. // Double deploy.
@ -44,7 +44,7 @@ func TestDeployGetUpdateDestroyContract(t *testing.T) {
require.Equal(t, int32(2), contract2.ID) require.Equal(t, int32(2), contract2.ID)
require.Equal(t, uint16(0), contract2.UpdateCounter) require.Equal(t, uint16(0), contract2.UpdateCounter)
require.Equal(t, state.CreateContractHash(sender2, script), contract2.Hash) require.Equal(t, state.CreateContractHash(sender2, script), contract2.Hash)
require.Equal(t, script, contract2.Script) require.Equal(t, ne, &contract2.NEF)
require.Equal(t, *manif, contract2.Manifest) require.Equal(t, *manif, contract2.Manifest)
refContract, err := mgmt.GetContract(d, h) refContract, err := mgmt.GetContract(d, h)

View file

@ -172,7 +172,7 @@ func TestNativeContract_Invoke(t *testing.T) {
err := chain.contracts.Management.PutContractState(chain.dao, &state.Contract{ err := chain.contracts.Management.PutContractState(chain.dao, &state.Contract{
ID: 1, ID: 1,
Script: tn.meta.Script, NEF: tn.meta.NEF,
Hash: tn.meta.Hash, Hash: tn.meta.Hash,
Manifest: tn.meta.Manifest, Manifest: tn.meta.Manifest,
}) })
@ -210,7 +210,7 @@ func TestNativeContract_InvokeInternal(t *testing.T) {
err := chain.contracts.Management.PutContractState(chain.dao, &state.Contract{ err := chain.contracts.Management.PutContractState(chain.dao, &state.Contract{
ID: 1, ID: 1,
Script: tn.meta.Script, NEF: tn.meta.NEF,
Manifest: tn.meta.Manifest, Manifest: tn.meta.Manifest,
}) })
require.NoError(t, err) require.NoError(t, err)
@ -252,7 +252,7 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) {
err := chain.contracts.Management.PutContractState(chain.dao, &state.Contract{ err := chain.contracts.Management.PutContractState(chain.dao, &state.Contract{
ID: 1, ID: 1,
Hash: tn.meta.Hash, Hash: tn.meta.Hash,
Script: tn.meta.Script, NEF: tn.meta.NEF,
Manifest: tn.meta.Manifest, Manifest: tn.meta.Manifest,
}) })
require.NoError(t, err) require.NoError(t, err)

View file

@ -36,10 +36,10 @@ func TestRestoreAfterDeploy(t *testing.T) {
mgmtHash := bc.ManagementContractHash() mgmtHash := bc.ManagementContractHash()
cs1, _ := getTestContractState(bc) cs1, _ := getTestContractState(bc)
cs1.ID = 1 cs1.ID = 1
cs1.Hash = state.CreateContractHash(testchain.MultisigScriptHash(), cs1.Script) cs1.Hash = state.CreateContractHash(testchain.MultisigScriptHash(), cs1.NEF.Script)
manif1, err := json.Marshal(cs1.Manifest) manif1, err := json.Marshal(cs1.Manifest)
require.NoError(t, err) require.NoError(t, err)
nef1, err := nef.NewFile(cs1.Script) nef1, err := nef.NewFile(cs1.NEF.Script)
require.NoError(t, err) require.NoError(t, err)
nef1b, err := nef1.Bytes() nef1b, err := nef1.Bytes()
require.NoError(t, err) require.NoError(t, err)
@ -80,10 +80,10 @@ func TestContractDeploy(t *testing.T) {
mgmtHash := bc.ManagementContractHash() mgmtHash := bc.ManagementContractHash()
cs1, _ := getTestContractState(bc) cs1, _ := getTestContractState(bc)
cs1.ID = 1 cs1.ID = 1
cs1.Hash = state.CreateContractHash(testchain.MultisigScriptHash(), cs1.Script) cs1.Hash = state.CreateContractHash(testchain.MultisigScriptHash(), cs1.NEF.Script)
manif1, err := json.Marshal(cs1.Manifest) manif1, err := json.Marshal(cs1.Manifest)
require.NoError(t, err) require.NoError(t, err)
nef1, err := nef.NewFile(cs1.Script) nef1, err := nef.NewFile(cs1.NEF.Script)
require.NoError(t, err) require.NoError(t, err)
nef1b, err := nef1.Bytes() nef1b, err := nef1.Bytes()
require.NoError(t, err) require.NoError(t, err)
@ -278,7 +278,7 @@ func TestContractUpdate(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
manif1, err := json.Marshal(cs1.Manifest) manif1, err := json.Marshal(cs1.Manifest)
require.NoError(t, err) require.NoError(t, err)
nef1, err := nef.NewFile(cs1.Script) nef1, err := nef.NewFile(cs1.NEF.Script)
require.NoError(t, err) require.NoError(t, err)
nef1b, err := nef1.Bytes() nef1b, err := nef1.Bytes()
require.NoError(t, err) require.NoError(t, err)
@ -322,10 +322,9 @@ func TestContractUpdate(t *testing.T) {
checkFAULTState(t, res) checkFAULTState(t, res)
}) })
cs1.Script = append(cs1.Script, byte(opcode.RET)) cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.RET))
nef1, err = nef.NewFile(cs1.Script) cs1.NEF.Checksum = cs1.NEF.CalculateChecksum()
require.NoError(t, err) nef1b, err = cs1.NEF.Bytes()
nef1b, err = nef1.Bytes()
require.NoError(t, err) require.NoError(t, err)
cs1.UpdateCounter++ cs1.UpdateCounter++
@ -376,10 +375,9 @@ func TestContractUpdate(t *testing.T) {
}) })
}) })
cs1.Script = append(cs1.Script, byte(opcode.ABORT)) cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.ABORT))
nef1, err = nef.NewFile(cs1.Script) cs1.NEF.Checksum = cs1.NEF.CalculateChecksum()
require.NoError(t, err) nef1b, err = cs1.NEF.Bytes()
nef1b, err = nef1.Bytes()
require.NoError(t, err) require.NoError(t, err)
cs1.Manifest.Extra = "update me once more" cs1.Manifest.Extra = "update me once more"
manif1, err = json.Marshal(cs1.Manifest) manif1, err = json.Marshal(cs1.Manifest)
@ -471,12 +469,14 @@ func compareContractStates(t *testing.T, expected *state.Contract, actual stacki
expectedManifest, err := json.Marshal(expected.Manifest) expectedManifest, err := json.Marshal(expected.Manifest)
require.NoError(t, err) require.NoError(t, err)
expectedNef, err := expected.NEF.Bytes()
require.NoError(t, err)
require.Equal(t, 5, len(act)) require.Equal(t, 5, len(act))
require.Equal(t, expected.ID, int32(act[0].Value().(*big.Int).Int64())) require.Equal(t, expected.ID, int32(act[0].Value().(*big.Int).Int64()))
require.Equal(t, expected.UpdateCounter, uint16(act[1].Value().(*big.Int).Int64())) require.Equal(t, expected.UpdateCounter, uint16(act[1].Value().(*big.Int).Int64()))
require.Equal(t, expected.Hash.BytesBE(), act[2].Value().([]byte)) require.Equal(t, expected.Hash.BytesBE(), act[2].Value().([]byte))
require.Equal(t, expected.Script, act[3].Value().([]byte)) require.Equal(t, expectedNef, act[3].Value().([]byte))
require.Equal(t, expectedManifest, act[4].Value().([]byte)) require.Equal(t, expectedManifest, act[4].Value().([]byte))
} }

View file

@ -17,6 +17,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
@ -83,8 +84,12 @@ func getOracleContractState(h util.Uint160) *state.Contract {
m.Permissions = append(m.Permissions, *perm) m.Permissions = append(m.Permissions, *perm)
script := w.Bytes() script := w.Bytes()
ne, err := nef.NewFile(script)
if err != nil {
panic(err)
}
return &state.Contract{ return &state.Contract{
Script: script, NEF: *ne,
Hash: hash.Hash160(script), Hash: hash.Hash160(script),
Manifest: *m, Manifest: *m,
ID: 42, ID: 42,

View file

@ -10,6 +10,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "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/opcode"
@ -21,7 +22,7 @@ type Contract struct {
ID int32 `json:"id"` ID int32 `json:"id"`
UpdateCounter uint16 `json:"updatecounter"` UpdateCounter uint16 `json:"updatecounter"`
Hash util.Uint160 `json:"hash"` Hash util.Uint160 `json:"hash"`
Script []byte `json:"script"` NEF nef.File `json:"nef"`
Manifest manifest.Manifest `json:"manifest"` Manifest manifest.Manifest `json:"manifest"`
} }
@ -50,11 +51,15 @@ func (c *Contract) ToStackItem() (stackitem.Item, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
rawNef, err := c.NEF.Bytes()
if err != nil {
return nil, err
}
return stackitem.NewArray([]stackitem.Item{ return stackitem.NewArray([]stackitem.Item{
stackitem.Make(c.ID), stackitem.Make(c.ID),
stackitem.Make(c.UpdateCounter), stackitem.Make(c.UpdateCounter),
stackitem.NewByteArray(c.Hash.BytesBE()), stackitem.NewByteArray(c.Hash.BytesBE()),
stackitem.NewByteArray(c.Script), stackitem.NewByteArray(rawNef),
stackitem.NewByteArray(manifest), stackitem.NewByteArray(manifest),
}), nil }), nil
} }
@ -94,8 +99,10 @@ func (c *Contract) FromStackItem(item stackitem.Item) error {
if err != nil { if err != nil {
return err return err
} }
c.Script = make([]byte, len(bytes)) c.NEF, err = nef.FileFromBytes(bytes)
copy(c.Script, bytes) if err != nil {
return err
}
bytes, err = arr[4].TryBytes() bytes, err = arr[4].TryBytes()
if err != nil { if err != nil {
return err return err

View file

@ -9,6 +9,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -37,9 +38,18 @@ func TestEncodeDecodeContractState(t *testing.T) {
ID: 123, ID: 123,
UpdateCounter: 42, UpdateCounter: 42,
Hash: h, Hash: h,
Script: script, NEF: nef.File{
Manifest: *m, Header: nef.Header{
Magic: nef.Magic,
Compiler: "neo-go.test",
Version: "test",
},
Script: script,
Checksum: 0,
},
Manifest: *m,
} }
contract.NEF.Checksum = contract.NEF.CalculateChecksum()
t.Run("Serializable", func(t *testing.T) { t.Run("Serializable", func(t *testing.T) {
contractDecoded := new(Contract) contractDecoded := new(Contract)
@ -67,7 +77,10 @@ func TestContractFromStackItem(t *testing.T) {
id = stackitem.Make(42) id = stackitem.Make(42)
counter = stackitem.Make(11) counter = stackitem.Make(11)
chash = stackitem.Make(util.Uint160{1, 2, 3}.BytesBE()) chash = stackitem.Make(util.Uint160{1, 2, 3}.BytesBE())
script = stackitem.Make([]byte{0, 9, 8}) script = []byte{0, 9, 8}
nefFile, _ = nef.NewFile(script)
rawNef, _ = nefFile.Bytes()
nefItem = stackitem.NewByteArray(rawNef)
manifest = manifest.DefaultManifest("stack item") manifest = manifest.DefaultManifest("stack item")
manifestB, _ = json.Marshal(manifest) manifestB, _ = json.Marshal(manifest)
manifItem = stackitem.Make(manifestB) manifItem = stackitem.Make(manifestB)
@ -77,15 +90,15 @@ func TestContractFromStackItem(t *testing.T) {
item stackitem.Item item stackitem.Item
}{ }{
{"not an array", stackitem.Make(1)}, {"not an array", stackitem.Make(1)},
{"id is not a number", stackitem.Make([]stackitem.Item{manifItem, counter, chash, script, manifItem})}, {"id is not a number", stackitem.Make([]stackitem.Item{manifItem, counter, chash, nefItem, manifItem})},
{"id is out of range", stackitem.Make([]stackitem.Item{stackitem.Make(math.MaxUint32), counter, chash, script, manifItem})}, {"id is out of range", stackitem.Make([]stackitem.Item{stackitem.Make(math.MaxUint32), counter, chash, nefItem, manifItem})},
{"counter is not a number", stackitem.Make([]stackitem.Item{id, manifItem, chash, script, manifItem})}, {"counter is not a number", stackitem.Make([]stackitem.Item{id, manifItem, chash, nefItem, manifItem})},
{"counter is out of range", stackitem.Make([]stackitem.Item{id, stackitem.Make(100500), chash, script, manifItem})}, {"counter is out of range", stackitem.Make([]stackitem.Item{id, stackitem.Make(100500), chash, nefItem, manifItem})},
{"hash is not a byte string", stackitem.Make([]stackitem.Item{id, counter, stackitem.NewArray(nil), script, manifItem})}, {"hash is not a byte string", stackitem.Make([]stackitem.Item{id, counter, stackitem.NewArray(nil), nefItem, manifItem})},
{"hash is not a hash", stackitem.Make([]stackitem.Item{id, counter, stackitem.Make([]byte{1, 2, 3}), script, manifItem})}, {"hash is not a hash", stackitem.Make([]stackitem.Item{id, counter, stackitem.Make([]byte{1, 2, 3}), nefItem, manifItem})},
{"script is not a byte string", stackitem.Make([]stackitem.Item{id, counter, chash, stackitem.NewArray(nil), manifItem})}, {"nef is not a byte string", stackitem.Make([]stackitem.Item{id, counter, chash, stackitem.NewArray(nil), manifItem})},
{"manifest is not a byte string", stackitem.Make([]stackitem.Item{id, counter, chash, script, stackitem.NewArray(nil)})}, {"manifest is not a byte string", stackitem.Make([]stackitem.Item{id, counter, chash, nefItem, stackitem.NewArray(nil)})},
{"manifest is not correct", stackitem.Make([]stackitem.Item{id, counter, chash, script, stackitem.Make(100500)})}, {"manifest is not correct", stackitem.Make([]stackitem.Item{id, counter, chash, nefItem, stackitem.Make(100500)})},
} }
) )
for _, cs := range badCases { for _, cs := range badCases {
@ -96,6 +109,6 @@ func TestContractFromStackItem(t *testing.T) {
}) })
} }
var c = new(Contract) var c = new(Contract)
err := c.FromStackItem(stackitem.Make([]stackitem.Item{id, counter, chash, script, manifItem})) err := c.FromStackItem(stackitem.Make([]stackitem.Item{id, counter, chash, nefItem, manifItem}))
require.NoError(t, err) require.NoError(t, err)
} }

View file

@ -27,6 +27,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
@ -329,7 +330,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
} }
return c.GetContractStateByHash(hash) return c.GetContractStateByHash(hash)
}, },
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"name":"Test","abi":{"methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`, 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"}}`,
result: func(c *Client) interface{} { result: func(c *Client) interface{} {
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==") script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
if err != nil { if err != nil {
@ -339,7 +340,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
cs := &state.Contract{ cs := &state.Contract{
ID: 0, ID: 0,
Hash: hash.Hash160(script), Hash: hash.Hash160(script),
Script: script, NEF: newTestNEF(script),
Manifest: *m, Manifest: *m,
} }
return cs return cs
@ -350,7 +351,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.GetContractStateByAddressOrName("NWiu5oejTu925aeL9Hc1LX8SvaJhE23h15") return c.GetContractStateByAddressOrName("NWiu5oejTu925aeL9Hc1LX8SvaJhE23h15")
}, },
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"name":"Test","abi":{"methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`, 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"}}`,
result: func(c *Client) interface{} { result: func(c *Client) interface{} {
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==") script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
if err != nil { if err != nil {
@ -360,7 +361,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
cs := &state.Contract{ cs := &state.Contract{
ID: 0, ID: 0,
Hash: hash.Hash160(script), Hash: hash.Hash160(script),
Script: script, NEF: newTestNEF(script),
Manifest: *m, Manifest: *m,
} }
return cs return cs
@ -371,7 +372,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.GetContractStateByID(0) return c.GetContractStateByID(0)
}, },
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":0,"script":"VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==","manifest":{"name":"Test","abi":{"methods":[],"events":[]},"groups":[],"permissions":null,"trusts":[],"supportedstandards":[],"safemethods":[],"extra":null},"hash":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176"}}`, 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"}}`,
result: func(c *Client) interface{} { result: func(c *Client) interface{} {
script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==") script, err := base64.StdEncoding.DecodeString("VgJXHwIMDWNvbnRyYWN0IGNhbGx4eVMTwEEFB5IWIXhKDANQdXSXJyQAAAAQVUGEGNYNIXJqeRDOeRHOU0FSoUH1IUURQCOPAgAASgwLdG90YWxTdXBwbHmXJxEAAABFAkBCDwBAI28CAABKDAhkZWNpbWFsc5cnDQAAAEUSQCNWAgAASgwEbmFtZZcnEgAAAEUMBFJ1YmxAIzwCAABKDAZzeW1ib2yXJxEAAABFDANSVUJAIyECAABKDAliYWxhbmNlT2aXJ2IAAAAQVUGEGNYNIXN5EM50bMoAFLQnIwAAAAwPaW52YWxpZCBhZGRyZXNzEVVBNtNSBiFFENsgQGtsUEEfLnsHIXUMCWJhbGFuY2VPZmxtUxPAQQUHkhYhRW1AI7IBAABKDAh0cmFuc2ZlcpcnKwEAABBVQYQY1g0hdnkQzncHbwfKABS0JyoAAAAMFmludmFsaWQgJ2Zyb20nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRHOdwhvCMoAFLQnKAAAAAwUaW52YWxpZCAndG8nIGFkZHJlc3MRVUE201IGIUUQ2yBAeRLOdwlvCRC1JyIAAAAMDmludmFsaWQgYW1vdW50EVVBNtNSBiFFENsgQG5vB1BBHy57ByF3Cm8Kbwm1JyYAAAAMEmluc3VmZmljaWVudCBmdW5kcxFVQTbTUgYhRRDbIEBvCm8Jn3cKbm8HbwpTQVKhQfUhbm8IUEEfLnsHIXcLbwtvCZ53C25vCG8LU0FSoUH1IQwIdHJhbnNmZXJvB28IbwlUFMBBBQeSFiFFEUAjewAAAEoMBGluaXSXJ1AAAAAQVUGEGNYNIXcMEFVBh8PSZCF3DQJAQg8Adw5vDG8Nbw5TQVKhQfUhDAh0cmFuc2ZlcgwA2zBvDW8OVBTAQQUHkhYhRRFAIyMAAAAMEWludmFsaWQgb3BlcmF0aW9uQTbTUgY6IwUAAABFQA==")
if err != nil { if err != nil {
@ -381,7 +382,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
cs := &state.Contract{ cs := &state.Contract{
ID: 0, ID: 0,
Hash: hash.Hash160(script), Hash: hash.Hash160(script),
Script: script, NEF: newTestNEF(script),
Manifest: *m, Manifest: *m,
} }
return cs return cs
@ -1627,3 +1628,13 @@ func TestUninitedClient(t *testing.T) {
_, err = c.GetFeePerByte() _, err = c.GetFeePerByte()
require.Error(t, err) require.Error(t, err)
} }
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.Script = script
ne.Checksum = ne.CalculateChecksum()
return ne
}

View file

@ -36,16 +36,16 @@ const (
// File represents compiled contract file structure according to the NEF3 standard. // File represents compiled contract file structure according to the NEF3 standard.
type File struct { type File struct {
Header Header Header
Script []byte Script []byte `json:"script"`
Checksum uint32 Checksum uint32 `json:"checksum"`
} }
// Header represents File header. // Header represents File header.
type Header struct { type Header struct {
Magic uint32 Magic uint32 `json:"magic"`
Compiler string Compiler string `json:"compiler"`
Version string Version string `json:"version"`
} }
// NewFile returns new NEF3 file with script specified. // NewFile returns new NEF3 file with script specified.

View file

@ -1,6 +1,9 @@
package nef package nef
import ( import (
"encoding/base64"
"encoding/json"
"strconv"
"testing" "testing"
"github.com/nspcc-dev/neo-go/internal/testserdes" "github.com/nspcc-dev/neo-go/internal/testserdes"
@ -74,3 +77,28 @@ func TestBytesFromBytes(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, expected, actual) require.Equal(t, expected, actual)
} }
func TestMarshalUnmarshalJSON(t *testing.T) {
expected := &File{
Header: Header{
Magic: Magic,
Compiler: "test.compiler",
Version: "test.ver",
},
Script: []byte{1, 2, 3, 4},
}
expected.Checksum = expected.CalculateChecksum()
data, err := json.Marshal(expected)
require.NoError(t, err)
require.JSONEq(t, `{
"magic":`+strconv.FormatUint(uint64(Magic), 10)+`,
"compiler": "test.compiler",
"version": "test.ver",
"script": "`+base64.StdEncoding.EncodeToString(expected.Script)+`",
"checksum":`+strconv.FormatUint(uint64(expected.Checksum), 10)+`}`, string(data))
actual := new(File)
require.NoError(t, json.Unmarshal(data, actual))
require.Equal(t, expected, actual)
}