diff --git a/cli/contract_test.go b/cli/contract_test.go index f8886d33c..556dd5cc7 100644 --- a/cli/contract_test.go +++ b/cli/contract_test.go @@ -17,6 +17,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result" + "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/vm" @@ -33,28 +34,37 @@ func TestCalcHash(t *testing.T) { require.NoError(t, err) nefF, err := nef.FileFromBytes(src) require.NoError(t, err) + manifestPath := "./testdata/verify.manifest.json" + manifestBytes, err := ioutil.ReadFile(manifestPath) + require.NoError(t, err) + manif := &manifest.Manifest{} + err = json.Unmarshal(manifestBytes, manif) + require.NoError(t, err) sender := random.Uint160() cmd := []string{"neo-go", "contract", "calc-hash"} t.Run("no sender", func(t *testing.T) { - e.RunWithError(t, append(cmd, "--in", nefPath)...) + e.RunWithError(t, append(cmd, "--in", nefPath, "--manifest", manifestPath)...) }) t.Run("no nef file", func(t *testing.T) { - e.RunWithError(t, append(cmd, "--sender", sender.StringLE())...) + e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--manifest", manifestPath)...) + }) + t.Run("no manifest file", func(t *testing.T) { + e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--in", nefPath)...) }) t.Run("invalid path", func(t *testing.T) { e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), - "--in", "./testdata/verify.nef123")...) + "--in", "./testdata/verify.nef123", "--manifest", manifestPath)...) }) t.Run("invalid file", func(t *testing.T) { p := path.Join(os.TempDir(), "neogo.calchash.verify.nef") defer os.Remove(p) require.NoError(t, ioutil.WriteFile(p, src[:4], os.ModePerm)) - e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--in", p)...) + e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--in", p, "--manifest", manifestPath)...) }) - cmd = append(cmd, "--in", nefPath) - expected := state.CreateContractHash(sender, nefF.Script) + cmd = append(cmd, "--in", nefPath, "--manifest", manifestPath) + expected := state.CreateContractHash(sender, nefF.Checksum, manif.Name) t.Run("valid, uint160", func(t *testing.T) { e.Run(t, append(cmd, "--sender", sender.StringLE())...) e.checkNextLine(t, expected.StringLE()) @@ -193,7 +203,8 @@ func TestComlileAndInvokeFunction(t *testing.T) { t.Run("check calc hash", func(t *testing.T) { e.Run(t, "neo-go", "contract", "calc-hash", - "--sender", validatorAddr, "--in", nefName) + "--sender", validatorAddr, "--in", nefName, + "--manifest", manifestName) e.checkNextLine(t, h.StringLE()) }) diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 681949158..a8d87a1d7 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -351,6 +351,10 @@ func NewCommands() []cli.Command { Name: "in", Usage: "path to NEF file", }, + cli.StringFlag{ + Name: "manifest, m", + Usage: "path to manifest file", + }, }, }, }, @@ -473,6 +477,10 @@ func calcHash(ctx *cli.Context) error { if p == "" { return cli.NewExitError(errors.New("no .nef file was provided"), 1) } + mpath := ctx.String("manifest") + if mpath == "" { + return cli.NewExitError(errors.New("no manifest file provided"), 1) + } f, err := ioutil.ReadFile(p) if err != nil { return cli.NewExitError(fmt.Errorf("can't read .nef file: %w", err), 1) @@ -481,7 +489,16 @@ func calcHash(ctx *cli.Context) error { if err != nil { return cli.NewExitError(fmt.Errorf("can't unmarshal .nef file: %w", err), 1) } - fmt.Fprintln(ctx.App.Writer, "Contract hash:", state.CreateContractHash(u, nefFile.Script).StringLE()) + manifestBytes, err := ioutil.ReadFile(mpath) + if err != nil { + return cli.NewExitError(fmt.Errorf("failed to read manifest file: %w", err), 1) + } + m := &manifest.Manifest{} + err = json.Unmarshal(manifestBytes, m) + if err != nil { + return cli.NewExitError(fmt.Errorf("failed to restore manifest file: %w", err), 1) + } + fmt.Fprintln(ctx.App.Writer, "Contract hash:", state.CreateContractHash(u, nefFile.Checksum, m.Name).StringLE()) return nil } @@ -842,7 +859,7 @@ func contractDeploy(ctx *cli.Context) error { if err != nil { return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %w", err), 1) } - hash := state.CreateContractHash(sender, nefFile.Script) + hash := state.CreateContractHash(sender, nefFile.Checksum, m.Name) fmt.Fprintf(ctx.App.Writer, "Contract: %s\n", hash.StringLE()) fmt.Fprintln(ctx.App.Writer, txHash.StringLE()) return nil diff --git a/cli/testdata/chain50x2.acc b/cli/testdata/chain50x2.acc index e78bd4eb9..830712741 100644 Binary files a/cli/testdata/chain50x2.acc and b/cli/testdata/chain50x2.acc differ diff --git a/internal/testchain/transaction.go b/internal/testchain/transaction.go index 2efcb70ad..8f8a4aa11 100644 --- a/internal/testchain/transaction.go +++ b/internal/testchain/transaction.go @@ -84,7 +84,7 @@ func NewDeployTx(bc blockchainer.Blockchainer, name string, sender util.Uint160, tx := transaction.New(Network(), buf.Bytes(), 100*native.GASFactor) tx.Signers = []transaction.Signer{{Account: sender}} - h := state.CreateContractHash(tx.Sender(), avm) + h := state.CreateContractHash(tx.Sender(), ne.Checksum, name) return tx, h, nil } diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index af8bfa062..83f83a971 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -556,11 +556,11 @@ func TestVerifyTx(t *testing.T) { }) tx.Scripts = append(tx.Scripts, transaction.Witness{}) t.Run("NonZeroVerification", func(t *testing.T) { - script, _ := state.CreateNativeContractHash(-6) //oracleContractID w := io.NewBufBinWriter() emit.Opcodes(w.BinWriter, opcode.ABORT) emit.Bytes(w.BinWriter, util.Uint160{}.BytesBE()) - emit.Bytes(w.BinWriter, script) + emit.Int(w.BinWriter, int64(orc.NEF.Checksum)) + emit.String(w.BinWriter, orc.Manifest.Name) tx.Scripts[len(tx.Scripts)-1].VerificationScript = w.Bytes() err := bc.VerifyTx(tx) require.True(t, errors.Is(err, ErrNativeContractWitness), "got: %v", err) diff --git a/pkg/core/interop/context.go b/pkg/core/interop/context.go index 02ac19bfb..c649d6984 100644 --- a/pkg/core/interop/context.go +++ b/pkg/core/interop/context.go @@ -119,8 +119,9 @@ func NewContractMD(name string, id int32) *ContractMD { // Therefore values are taken from C# node. c.NEF.Header.Compiler = "neo-core-v3.0" c.NEF.Header.Magic = nef.Magic - c.NEF.Script, c.Hash = state.CreateNativeContractHash(id) + c.NEF.Script = state.CreateNativeContractScript(id) c.NEF.Checksum = c.NEF.CalculateChecksum() + c.Hash = state.CreateContractHash(util.Uint160{}, c.NEF.Checksum, name) c.Manifest = *manifest.DefaultManifest(name) return c diff --git a/pkg/core/native/compatibility_test.go b/pkg/core/native/compatibility_test.go index d027377f8..de96eb982 100644 --- a/pkg/core/native/compatibility_test.go +++ b/pkg/core/native/compatibility_test.go @@ -8,12 +8,12 @@ import ( // Compatibility test. hashes are taken directly from C# node. func TestNativeHashes(t *testing.T) { - require.Equal(t, "bee421fdbb3e791265d2104cb34934f53fcc0e45", newManagement().Hash.StringLE()) - require.Equal(t, "4961bf0ab79370b23dc45cde29f568d0e0fa6e93", newNEO().Hash.StringLE()) - require.Equal(t, "9ac04cf223f646de5f7faccafe34e30e5d4382a2", newGAS().Hash.StringLE()) - require.Equal(t, "c939a4af1c762e5edca36d4b61c06ba82c4c6ff5", newPolicy().Hash.StringLE()) - require.Equal(t, "f4bbd95569e8dda2cb84eb609a1488ddd0d9fa91", newDesignate(false).Hash.StringLE()) - require.Equal(t, "8cd3889136056b3304ec59f6d424b8767710ed79", newOracle().Hash.StringLE()) + require.Equal(t, "a501d7d7d10983673b61b7a2d3a813b36f9f0e43", newManagement().Hash.StringLE()) + require.Equal(t, "f617baca689d1abddedda7c3b80675c4ac21e932", newNEO().Hash.StringLE()) + require.Equal(t, "75844530eb44f4715a42950bb59b4d7ace0b2f3d", newGAS().Hash.StringLE()) + require.Equal(t, "e21a28cfc1e662e152f668c86198141cc17b6c37", newPolicy().Hash.StringLE()) + require.Equal(t, "69b1909aaa14143b0624ba0d61d5cd3b8b67529d", newDesignate(false).Hash.StringLE()) + require.Equal(t, "b82bbf650f963dbf71577d10ea4077e711a13e7b", newOracle().Hash.StringLE()) // Not yet a part of NEO. //require.Equal(t, "", newNotary().Hash.StringLE()()) } diff --git a/pkg/core/native/management.go b/pkg/core/native/management.go index 1face8fc9..f25843c81 100644 --- a/pkg/core/native/management.go +++ b/pkg/core/native/management.go @@ -239,7 +239,7 @@ func (m *Management) markUpdated(h util.Uint160) { // Deploy creates contract's hash/ID and saves new contract into the given DAO. // It doesn't run _deploy method and doesn't emit notification. func (m *Management) Deploy(d dao.DAO, sender util.Uint160, neff *nef.File, manif *manifest.Manifest) (*state.Contract, error) { - h := state.CreateContractHash(sender, neff.Script) + h := state.CreateContractHash(sender, neff.Checksum, manif.Name) key := makeContractKey(h) si := d.GetStorageItem(m.ContractID, key) if si != nil { diff --git a/pkg/core/native/management_test.go b/pkg/core/native/management_test.go index 8d1571baa..fa654e985 100644 --- a/pkg/core/native/management_test.go +++ b/pkg/core/native/management_test.go @@ -18,13 +18,13 @@ func TestDeployGetUpdateDestroyContract(t *testing.T) { d := dao.NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet, false) script := []byte{1} sender := util.Uint160{1, 2, 3} - h := state.CreateContractHash(sender, script) - ne, err := nef.NewFile(script) require.NoError(t, err) manif := manifest.NewManifest("Test") require.NoError(t, err) + h := state.CreateContractHash(sender, ne.Checksum, manif.Name) + contract, err := mgmt.Deploy(d, sender, ne, manif) require.NoError(t, err) require.Equal(t, int32(1), contract.ID) @@ -43,7 +43,7 @@ func TestDeployGetUpdateDestroyContract(t *testing.T) { require.NoError(t, err) require.Equal(t, int32(2), contract2.ID) require.Equal(t, uint16(0), contract2.UpdateCounter) - require.Equal(t, state.CreateContractHash(sender2, script), contract2.Hash) + require.Equal(t, state.CreateContractHash(sender2, ne.Checksum, manif.Name), contract2.Hash) require.Equal(t, ne, &contract2.NEF) require.Equal(t, *manif, contract2.Manifest) diff --git a/pkg/core/native_management_test.go b/pkg/core/native_management_test.go index 687998e1f..eb94d5bf9 100644 --- a/pkg/core/native_management_test.go +++ b/pkg/core/native_management_test.go @@ -36,7 +36,7 @@ func TestRestoreAfterDeploy(t *testing.T) { mgmtHash := bc.ManagementContractHash() cs1, _ := getTestContractState(bc) cs1.ID = 1 - cs1.Hash = state.CreateContractHash(testchain.MultisigScriptHash(), cs1.NEF.Script) + cs1.Hash = state.CreateContractHash(testchain.MultisigScriptHash(), cs1.NEF.Checksum, cs1.Manifest.Name) manif1, err := json.Marshal(cs1.Manifest) require.NoError(t, err) nef1, err := nef.NewFile(cs1.NEF.Script) @@ -80,7 +80,7 @@ func TestContractDeploy(t *testing.T) { mgmtHash := bc.ManagementContractHash() cs1, _ := getTestContractState(bc) cs1.ID = 1 - cs1.Hash = state.CreateContractHash(testchain.MultisigScriptHash(), cs1.NEF.Script) + cs1.Hash = state.CreateContractHash(testchain.MultisigScriptHash(), cs1.NEF.Checksum, cs1.Manifest.Name) manif1, err := json.Marshal(cs1.Manifest) require.NoError(t, err) nef1b, err := cs1.NEF.Bytes() @@ -214,7 +214,7 @@ func TestContractDeploy(t *testing.T) { checkFAULTState(t, res) t.Run("get after failed deploy", func(t *testing.T) { - h := state.CreateContractHash(neoOwner, deployScript) + h := state.CreateContractHash(neoOwner, nefD.Checksum, m.Name) checkContractState(t, bc, h, nil) }) }) @@ -243,7 +243,7 @@ func TestContractDeploy(t *testing.T) { checkFAULTState(t, res) t.Run("get after bad _deploy", func(t *testing.T) { - h := state.CreateContractHash(neoOwner, deployScript) + h := state.CreateContractHash(neoOwner, nefD.Checksum, m.Name) checkContractState(t, bc, h, nil) }) }) diff --git a/pkg/core/state/contract.go b/pkg/core/state/contract.go index ab5e028ab..a3cf8cf03 100644 --- a/pkg/core/state/contract.go +++ b/pkg/core/state/contract.go @@ -112,25 +112,25 @@ func (c *Contract) FromStackItem(item stackitem.Item) error { // CreateContractHash creates deployed contract hash from transaction sender // and contract script. -func CreateContractHash(sender util.Uint160, script []byte) util.Uint160 { +func CreateContractHash(sender util.Uint160, checksum uint32, name string) util.Uint160 { w := io.NewBufBinWriter() emit.Opcodes(w.BinWriter, opcode.ABORT) emit.Bytes(w.BinWriter, sender.BytesBE()) - emit.Bytes(w.BinWriter, script) + emit.Int(w.BinWriter, int64(checksum)) + emit.String(w.BinWriter, name) if w.Err != nil { panic(w.Err) } return hash.Hash160(w.Bytes()) } -// CreateNativeContractHash returns script and hash for the native contract. -func CreateNativeContractHash(id int32) ([]byte, util.Uint160) { +// CreateNativeContractScript returns script for the native contract. +func CreateNativeContractScript(id int32) []byte { w := io.NewBufBinWriter() emit.Int(w.BinWriter, int64(id)) emit.Syscall(w.BinWriter, interopnames.SystemContractCallNative) if w.Err != nil { panic(w.Err) } - script := w.Bytes() - return script, CreateContractHash(util.Uint160{}, script) + return w.Bytes() } diff --git a/pkg/core/state/contract_test.go b/pkg/core/state/contract_test.go index 5d4c224f1..6f102a9e5 100644 --- a/pkg/core/state/contract_test.go +++ b/pkg/core/state/contract_test.go @@ -62,14 +62,22 @@ func TestEncodeDecodeContractState(t *testing.T) { } func TestCreateContractHash(t *testing.T) { - var script = []byte{1, 2, 3} + var neff = nef.File{ + Header: nef.Header{ + Compiler: "test", + Magic: nef.Magic, + }, + Tokens: []nef.MethodToken{}, + Script: []byte{1, 2, 3}, + } var sender util.Uint160 var err error - require.Equal(t, "b8e95ff7b11c427c29355e3398722d97bd2ca069", CreateContractHash(sender, script).StringLE()) + neff.Checksum = neff.CalculateChecksum() + require.Equal(t, "9b9628e4f1611af90e761eea8cc21372380c74b6", CreateContractHash(sender, neff.Checksum, "").StringLE()) sender, err = util.Uint160DecodeStringLE("a400ff00ff00ff00ff00ff00ff00ff00ff00ff01") require.NoError(t, err) - require.Equal(t, "435c467b8e15cb9b1474ad7ee817ffdcfededef9", CreateContractHash(sender, script).StringLE()) + require.Equal(t, "66eec404d86b918d084e62a29ac9990e3b6f4286", CreateContractHash(sender, neff.Checksum, "").StringLE()) } func TestContractFromStackItem(t *testing.T) { diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index 259321b3f..f88d5a985 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -56,11 +56,11 @@ type rpcTestCase struct { check func(t *testing.T, e *executor, result interface{}) } -const testContractHash = "0b3bc97e94ed99e32dda46c9ecd2d3626979af06" -const deploymentTxHash = "e3a67acac29014dc8c24773752ac4535a0f020486749ec5c907234fc9328246c" +const testContractHash = "c6436aab21ebd15279b85af8d7b5808d38455b0a" +const deploymentTxHash = "e6ffce4533231c4efdea9a65c7abc0e7073d96a4ebc66f402db3a84b6f8939ef" const genesisBlockHash = "0542f4350c6e236d0509bcd98188b0034bfbecc1a0c7fcdb8e4295310d468b70" -const verifyContractHash = "d2da8ee8c0bf6c5bf3dda1ef671dbf5fef7226e9" +const verifyContractHash = "03ffc0897543b9b709e0f8cab4a7682dae0ba943" const verifyContractAVM = "570300412d51083021700c14aa8acf859d4fe402b34e673f2156821796a488ebdb30716813cedb2869db289740" const testVerifyContractAVM = "VwcADBQBDAMOBQYMDQIODw0DDgcJAAAAANswcGgRVUH4J+yMIaonBwAAABFADBQNDwMCCQACAQMHAwQFAgEADgYMCdswcWkRVUH4J+yMIaonBwAAABJAE0A=" diff --git a/pkg/rpc/server/testdata/testblocks.acc b/pkg/rpc/server/testdata/testblocks.acc index f3e5350c9..ac9b113ac 100644 Binary files a/pkg/rpc/server/testdata/testblocks.acc and b/pkg/rpc/server/testdata/testblocks.acc differ