github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/native/native_test/management_test.go (about)

     1  package native_test
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"testing"
     8  
     9  	ojson "github.com/nspcc-dev/go-ordered-json"
    10  	"github.com/nspcc-dev/neo-go/internal/contracts"
    11  	"github.com/nspcc-dev/neo-go/pkg/config"
    12  	"github.com/nspcc-dev/neo-go/pkg/core/chaindump"
    13  	"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
    14  	"github.com/nspcc-dev/neo-go/pkg/core/native"
    15  	"github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
    16  	"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
    17  	"github.com/nspcc-dev/neo-go/pkg/core/state"
    18  	"github.com/nspcc-dev/neo-go/pkg/core/storage"
    19  	"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
    20  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    21  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    22  	"github.com/nspcc-dev/neo-go/pkg/io"
    23  	"github.com/nspcc-dev/neo-go/pkg/neotest"
    24  	"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
    25  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    26  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
    27  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
    28  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
    29  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
    30  	"github.com/nspcc-dev/neo-go/pkg/vm/emit"
    31  	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
    32  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    33  	"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
    34  	"github.com/stretchr/testify/require"
    35  )
    36  
    37  var (
    38  	// defaultCSS holds serialized native contract states built for genesis block (with UpdateCounter 0)
    39  	// under assumption that all hardforks are disabled.
    40  	defaultCSS = map[string]string{
    41  		nativenames.Management:  `{"id":-1,"hash":"0xfffdc93764dbaddd97c48f252a53ea4643faa3fd","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"ContractManagement","abi":{"methods":[{"name":"deploy","offset":0,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Array","safe":false},{"name":"deploy","offset":7,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Array","safe":false},{"name":"destroy","offset":14,"parameters":[],"returntype":"Void","safe":false},{"name":"getContract","offset":21,"parameters":[{"name":"hash","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getContractById","offset":28,"parameters":[{"name":"id","type":"Integer"}],"returntype":"Array","safe":true},{"name":"getContractHashes","offset":35,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getMinimumDeploymentFee","offset":42,"parameters":[],"returntype":"Integer","safe":true},{"name":"hasMethod","offset":49,"parameters":[{"name":"hash","type":"Hash160"},{"name":"method","type":"String"},{"name":"pcount","type":"Integer"}],"returntype":"Boolean","safe":true},{"name":"setMinimumDeploymentFee","offset":56,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"update","offset":63,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"update","offset":70,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false}],"events":[{"name":"Deploy","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Update","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Destroy","parameters":[{"name":"Hash","type":"Hash160"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
    42  		nativenames.StdLib:      `{"id":-2,"hash":"0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":1991619121},"manifest":{"name":"StdLib","abi":{"methods":[{"name":"atoi","offset":0,"parameters":[{"name":"value","type":"String"}],"returntype":"Integer","safe":true},{"name":"atoi","offset":7,"parameters":[{"name":"value","type":"String"},{"name":"base","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"base58CheckDecode","offset":14,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base58CheckEncode","offset":21,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"base58Decode","offset":28,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base58Encode","offset":35,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"base64Decode","offset":42,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base64Encode","offset":49,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"deserialize","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"itoa","offset":63,"parameters":[{"name":"value","type":"Integer"}],"returntype":"String","safe":true},{"name":"itoa","offset":70,"parameters":[{"name":"value","type":"Integer"},{"name":"base","type":"Integer"}],"returntype":"String","safe":true},{"name":"jsonDeserialize","offset":77,"parameters":[{"name":"json","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"jsonSerialize","offset":84,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"memoryCompare","offset":91,"parameters":[{"name":"str1","type":"ByteArray"},{"name":"str2","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":98,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":105,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":112,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"},{"name":"backward","type":"Boolean"}],"returntype":"Integer","safe":true},{"name":"serialize","offset":119,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"strLen","offset":126,"parameters":[{"name":"str","type":"String"}],"returntype":"Integer","safe":true},{"name":"stringSplit","offset":133,"parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"}],"returntype":"Array","safe":true},{"name":"stringSplit","offset":140,"parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"},{"name":"removeEmptyEntries","type":"Boolean"}],"returntype":"Array","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
    43  		nativenames.CryptoLib:   `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":2135988409},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":42,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":49,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":63,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curveHash","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
    44  		nativenames.Ledger:      `{"id":-4,"hash":"0xda65b600f7124ce6c79950c1772a36403104f2be","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"LedgerContract","abi":{"methods":[{"name":"currentHash","offset":0,"parameters":[],"returntype":"Hash256","safe":true},{"name":"currentIndex","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getBlock","offset":14,"parameters":[{"name":"indexOrHash","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"getTransaction","offset":21,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","safe":true},{"name":"getTransactionFromBlock","offset":28,"parameters":[{"name":"blockIndexOrHash","type":"ByteArray"},{"name":"txIndex","type":"Integer"}],"returntype":"Array","safe":true},{"name":"getTransactionHeight","offset":35,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","safe":true},{"name":"getTransactionSigners","offset":42,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","safe":true},{"name":"getTransactionVMState","offset":49,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
    45  		nativenames.Neo:         `{"id":-5,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":65467259},"manifest":{"name":"NeoToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getAccountState","offset":14,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getAllCandidates","offset":21,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getCandidateVote","offset":28,"parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","safe":true},{"name":"getCandidates","offset":35,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommittee","offset":42,"parameters":[],"returntype":"Array","safe":true},{"name":"getGasPerBlock","offset":49,"parameters":[],"returntype":"Integer","safe":true},{"name":"getNextBlockValidators","offset":56,"parameters":[],"returntype":"Array","safe":true},{"name":"getRegisterPrice","offset":63,"parameters":[],"returntype":"Integer","safe":true},{"name":"registerCandidate","offset":70,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"setGasPerBlock","offset":77,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setRegisterPrice","offset":84,"parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","safe":false},{"name":"symbol","offset":91,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":98,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":105,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false},{"name":"unclaimedGas","offset":112,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"unregisterCandidate","offset":119,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"vote","offset":126,"parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"trusts":[],"extra":null},"updatecounter":0}`,
    46  		nativenames.Gas:         `{"id":-6,"hash":"0xd2a4cff31913016155e38e474a2c06d08be276cf","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"GasToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"symbol","offset":14,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":21,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":28,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"trusts":[],"extra":null},"updatecounter":0}`,
    47  		nativenames.Policy:      `{"id":-7,"hash":"0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"PolicyContract","abi":{"methods":[{"name":"blockAccount","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false},{"name":"getAttributeFee","offset":7,"parameters":[{"name":"attributeType","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"getExecFeeFactor","offset":14,"parameters":[],"returntype":"Integer","safe":true},{"name":"getFeePerByte","offset":21,"parameters":[],"returntype":"Integer","safe":true},{"name":"getStoragePrice","offset":28,"parameters":[],"returntype":"Integer","safe":true},{"name":"isBlocked","offset":35,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":true},{"name":"setAttributeFee","offset":42,"parameters":[{"name":"attributeType","type":"Integer"},{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setExecFeeFactor","offset":49,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setFeePerByte","offset":56,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setStoragePrice","offset":63,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"unblockAccount","offset":70,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
    48  		nativenames.Designation: `{"id":-8,"hash":"0x49cf4e5378ffcd4dec034fd98a174c5491e395e2","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0A=","checksum":983638438},"manifest":{"name":"RoleManagement","abi":{"methods":[{"name":"designateAsRole","offset":0,"parameters":[{"name":"role","type":"Integer"},{"name":"nodes","type":"Array"}],"returntype":"Void","safe":false},{"name":"getDesignatedByRole","offset":7,"parameters":[{"name":"role","type":"Integer"},{"name":"index","type":"Integer"}],"returntype":"Array","safe":true}],"events":[{"name":"Designation","parameters":[{"name":"Role","type":"Integer"},{"name":"BlockIndex","type":"Integer"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
    49  		nativenames.Oracle:      `{"id":-9,"hash":"0xfe924b7cfe89ddd271abaf7210a80a7e11178758","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"OracleContract","abi":{"methods":[{"name":"finish","offset":0,"parameters":[],"returntype":"Void","safe":false},{"name":"getPrice","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"request","offset":14,"parameters":[{"name":"url","type":"String"},{"name":"filter","type":"String"},{"name":"callback","type":"String"},{"name":"userData","type":"Any"},{"name":"gasForResponse","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setPrice","offset":21,"parameters":[{"name":"price","type":"Integer"}],"returntype":"Void","safe":false},{"name":"verify","offset":28,"parameters":[],"returntype":"Boolean","safe":true}],"events":[{"name":"OracleRequest","parameters":[{"name":"Id","type":"Integer"},{"name":"RequestContract","type":"Hash160"},{"name":"Url","type":"String"},{"name":"Filter","type":"String"}]},{"name":"OracleResponse","parameters":[{"name":"Id","type":"Integer"},{"name":"OriginalTx","type":"Hash256"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
    50  		nativenames.Notary:      `{"id":-10,"hash":"0xc1e14f19c3e60d0b9244d06dd7ba9b113135ec3b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"Notary","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"addr","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"expirationOf","offset":7,"parameters":[{"name":"addr","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"getMaxNotValidBeforeDelta","offset":14,"parameters":[],"returntype":"Integer","safe":true},{"name":"lockDepositUntil","offset":21,"parameters":[{"name":"address","type":"Hash160"},{"name":"till","type":"Integer"}],"returntype":"Boolean","safe":false},{"name":"onNEP17Payment","offset":28,"parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"setMaxNotValidBeforeDelta","offset":35,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"verify","offset":42,"parameters":[{"name":"signature","type":"Signature"}],"returntype":"Boolean","safe":true},{"name":"withdraw","offset":49,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
    51  	}
    52  	// cockatriceCSS holds serialized native contract states built for genesis block (with UpdateCounter 0)
    53  	// under assumption that hardforks from Aspidochelone to Cockatrice (included) are enabled.
    54  	cockatriceCSS = map[string]string{
    55  		nativenames.CryptoLib: `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"keccak256","offset":42,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":49,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":63,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":70,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curveHash","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
    56  		nativenames.Neo:       `{"id":-5,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1325686241},"manifest":{"name":"NeoToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getAccountState","offset":14,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getAllCandidates","offset":21,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getCandidateVote","offset":28,"parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","safe":true},{"name":"getCandidates","offset":35,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommittee","offset":42,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommitteeAddress","offset":49,"parameters":[],"returntype":"Hash160","safe":true},{"name":"getGasPerBlock","offset":56,"parameters":[],"returntype":"Integer","safe":true},{"name":"getNextBlockValidators","offset":63,"parameters":[],"returntype":"Array","safe":true},{"name":"getRegisterPrice","offset":70,"parameters":[],"returntype":"Integer","safe":true},{"name":"registerCandidate","offset":77,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"setGasPerBlock","offset":84,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setRegisterPrice","offset":91,"parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","safe":false},{"name":"symbol","offset":98,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":105,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":112,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false},{"name":"unclaimedGas","offset":119,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"unregisterCandidate","offset":126,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"vote","offset":133,"parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"trusts":[],"extra":null},"updatecounter":0}`,
    57  	}
    58  )
    59  
    60  func init() {
    61  	for k, v := range defaultCSS {
    62  		if _, ok := cockatriceCSS[k]; !ok {
    63  			cockatriceCSS[k] = v
    64  		}
    65  	}
    66  }
    67  
    68  func newManagementClient(t *testing.T) *neotest.ContractInvoker {
    69  	return newNativeClient(t, nativenames.Management)
    70  }
    71  
    72  // newCustomManagementClient returns native Management invoker backed with chain with
    73  // specified custom configuration.
    74  func newCustomManagementClient(t *testing.T, f func(cfg *config.Blockchain)) *neotest.ContractInvoker {
    75  	return newCustomNativeClient(t, nativenames.Management, f)
    76  }
    77  
    78  func TestManagement_MinimumDeploymentFee(t *testing.T) {
    79  	testGetSet(t, newManagementClient(t), "MinimumDeploymentFee", 10_00000000, 0, 0)
    80  }
    81  
    82  func TestManagement_MinimumDeploymentFeeCache(t *testing.T) {
    83  	c := newManagementClient(t)
    84  	testGetSetCache(t, c, "MinimumDeploymentFee", 10_00000000)
    85  }
    86  
    87  func TestManagement_GenesisNativeState(t *testing.T) {
    88  	// check ensures that contract state stored in native Management matches the expected one.
    89  	check := func(t *testing.T, c *neotest.ContractInvoker, expected map[string]string) {
    90  		for _, name := range nativenames.All {
    91  			h := state.CreateNativeContractHash(name)
    92  			c.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
    93  				si := stack[0]
    94  				var cs = &state.Contract{}
    95  				require.NoError(t, cs.FromStackItem(si), name)
    96  				jBytes, err := ojson.Marshal(cs)
    97  				require.NoError(t, err)
    98  				require.Equal(t, expected[name], string(jBytes), fmt.Errorf("contract %s state mismatch", name))
    99  			}, "getContract", h.BytesBE())
   100  		}
   101  	}
   102  
   103  	t.Run("disabled hardforks", func(t *testing.T) {
   104  		mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
   105  			cfg.Hardforks = map[string]uint32{}
   106  			cfg.P2PSigExtensions = true
   107  		})
   108  		check(t, mgmt, defaultCSS)
   109  	})
   110  	t.Run("remotely enabled hardforks", func(t *testing.T) {
   111  		mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
   112  			cfg.Hardforks = map[string]uint32{
   113  				config.HFAspidochelone.String(): 100500,
   114  				config.HFBasilisk.String():      100500,
   115  				config.HFCockatrice.String():    100500,
   116  			}
   117  			cfg.P2PSigExtensions = true
   118  		})
   119  		check(t, mgmt, defaultCSS)
   120  	})
   121  	t.Run("Aspidochelone enabled", func(t *testing.T) {
   122  		mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
   123  			cfg.Hardforks = map[string]uint32{
   124  				config.HFAspidochelone.String(): 0,
   125  			}
   126  			cfg.P2PSigExtensions = true
   127  		})
   128  		check(t, mgmt, defaultCSS)
   129  	})
   130  	t.Run("Basilisk enabled", func(t *testing.T) {
   131  		mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
   132  			cfg.Hardforks = map[string]uint32{
   133  				config.HFAspidochelone.String(): 0,
   134  				config.HFBasilisk.String():      0,
   135  			}
   136  			cfg.P2PSigExtensions = true
   137  		})
   138  		check(t, mgmt, defaultCSS)
   139  	})
   140  	t.Run("Cockatrice enabled", func(t *testing.T) {
   141  		mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
   142  			cfg.Hardforks = map[string]uint32{
   143  				config.HFAspidochelone.String(): 0,
   144  				config.HFBasilisk.String():      0,
   145  				config.HFCockatrice.String():    0,
   146  			}
   147  			cfg.P2PSigExtensions = true
   148  		})
   149  		check(t, mgmt, cockatriceCSS)
   150  	})
   151  }
   152  
   153  func TestManagement_NativeDeployUpdateNotifications(t *testing.T) {
   154  	const cockatriceHeight = 3
   155  	mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
   156  		cfg.Hardforks = map[string]uint32{
   157  			config.HFAspidochelone.String(): 0,
   158  			config.HFBasilisk.String():      0,
   159  			config.HFCockatrice.String():    cockatriceHeight,
   160  		}
   161  		cfg.P2PSigExtensions = true
   162  	})
   163  	e := mgmt.Executor
   164  
   165  	// Check Deploy notifications.
   166  	aer, err := mgmt.Chain.GetAppExecResults(e.GetBlockByIndex(t, 0).Hash(), trigger.OnPersist)
   167  	require.NoError(t, err)
   168  	require.Equal(t, 1, len(aer))
   169  	var expected []state.NotificationEvent
   170  	for _, name := range nativenames.All {
   171  		switch name {
   172  		case nativenames.Gas:
   173  			expected = append(expected, state.NotificationEvent{
   174  				ScriptHash: nativehashes.GasToken,
   175  				Name:       "Transfer",
   176  				Item: stackitem.NewArray([]stackitem.Item{
   177  					stackitem.Null{},
   178  					stackitem.Make(mgmt.Validator.ScriptHash()),
   179  					stackitem.Make(mgmt.Chain.GetConfig().InitialGASSupply),
   180  				}),
   181  			})
   182  		case nativenames.Neo:
   183  			expected = append(expected, state.NotificationEvent{
   184  				ScriptHash: nativehashes.NeoToken,
   185  				Name:       "Transfer",
   186  				Item: stackitem.NewArray([]stackitem.Item{
   187  					stackitem.Null{},
   188  					stackitem.Make(mgmt.Validator.ScriptHash()),
   189  					stackitem.Make(native.NEOTotalSupply),
   190  				}),
   191  			})
   192  		}
   193  		expected = append(expected, state.NotificationEvent{
   194  			ScriptHash: nativehashes.ContractManagement,
   195  			Name:       "Deploy",
   196  			Item: stackitem.NewArray([]stackitem.Item{
   197  				stackitem.Make(state.CreateNativeContractHash(name)),
   198  			}),
   199  		})
   200  	}
   201  	require.Equal(t, expected, aer[0].Events)
   202  
   203  	// Generate some blocks and check Update notifications.
   204  	cockatriceBlock := mgmt.GenerateNewBlocks(t, cockatriceHeight)[cockatriceHeight-1]
   205  	aer, err = mgmt.Chain.GetAppExecResults(cockatriceBlock.Hash(), trigger.OnPersist)
   206  	require.NoError(t, err)
   207  	require.Equal(t, 1, len(aer))
   208  	expected = expected[:0]
   209  	for _, name := range []string{nativenames.CryptoLib, nativenames.Neo} {
   210  		expected = append(expected, state.NotificationEvent{
   211  			ScriptHash: nativehashes.ContractManagement,
   212  			Name:       "Update",
   213  			Item: stackitem.NewArray([]stackitem.Item{
   214  				stackitem.Make(state.CreateNativeContractHash(name)),
   215  			}),
   216  		})
   217  	}
   218  	require.Equal(t, expected, aer[0].Events)
   219  }
   220  
   221  func TestManagement_NativeUpdate(t *testing.T) {
   222  	const cockatriceHeight = 3
   223  	c := newCustomManagementClient(t, func(cfg *config.Blockchain) {
   224  		cfg.Hardforks = map[string]uint32{
   225  			config.HFAspidochelone.String(): 0,
   226  			config.HFBasilisk.String():      0,
   227  			config.HFCockatrice.String():    cockatriceHeight,
   228  		}
   229  		cfg.P2PSigExtensions = true
   230  	})
   231  
   232  	// Add some blocks up to the Cockatrice enabling height and check the default natives state.
   233  	for i := 0; i < cockatriceHeight-1; i++ {
   234  		c.AddNewBlock(t)
   235  		for _, name := range nativenames.All {
   236  			h := state.CreateNativeContractHash(name)
   237  			cs := c.Chain.GetContractState(h)
   238  			require.NotNil(t, cs, name)
   239  			jBytes, err := ojson.Marshal(cs)
   240  			require.NoError(t, err, name)
   241  			require.Equal(t, defaultCSS[name], string(jBytes), fmt.Errorf("contract %s state mismatch", name))
   242  		}
   243  	}
   244  
   245  	// Add Cockatrice block and check the updated native state.
   246  	c.AddNewBlock(t)
   247  	for _, name := range nativenames.All {
   248  		h := state.CreateNativeContractHash(name)
   249  		cs := c.Chain.GetContractState(h)
   250  		require.NotNil(t, cs, name)
   251  		if name == nativenames.Neo || name == nativenames.CryptoLib {
   252  			// A tiny hack to reuse cockatriceCSS map in the check below.
   253  			require.Equal(t, uint16(1), cs.UpdateCounter, name)
   254  			cs.UpdateCounter--
   255  		}
   256  		jBytes, err := ojson.Marshal(cs)
   257  		require.NoError(t, err, name)
   258  		require.Equal(t, cockatriceCSS[name], string(jBytes), fmt.Errorf("contract %s state mismatch", name))
   259  	}
   260  }
   261  
   262  func TestManagement_NativeUpdate_Call(t *testing.T) {
   263  	const (
   264  		cockatriceHeight = 3
   265  		method           = "getCommitteeAddress"
   266  	)
   267  	c := newCustomNativeClient(t, nativenames.Neo, func(cfg *config.Blockchain) {
   268  		cfg.Hardforks = map[string]uint32{
   269  			config.HFAspidochelone.String(): 0,
   270  			config.HFBasilisk.String():      0,
   271  			config.HFCockatrice.String():    cockatriceHeight,
   272  		}
   273  		cfg.P2PSigExtensions = true
   274  	})
   275  
   276  	// Invoke Cockatrice-dependant method before Cockatrice should fail.
   277  	for i := 0; i < cockatriceHeight-1; i++ {
   278  		c.InvokeFail(t, "at instruction 45 (SYSCALL): System.Contract.Call failed: method not found: getCommitteeAddress/0", method)
   279  	}
   280  
   281  	// Invoke Cockatrice-dependant method at Cockatrice should be OK.
   282  	tx := c.NewUnsignedTx(t, c.Hash, method)
   283  	c.SignTx(t, tx, 1_0000_0000, c.Signers...)
   284  	c.AddNewBlock(t, tx)
   285  	c.CheckHalt(t, tx.Hash(), stackitem.Make(c.CommitteeHash))
   286  
   287  	// Invoke Cockatrice-dependant method after Cockatrice should be OK.
   288  	c.Invoke(t, c.CommitteeHash, method)
   289  }
   290  
   291  // TestBlockchain_GetNatives ensures that Blockchain's GetNatives API works as expected with
   292  // different block heights depending on hardfork settings. This test is located here since it
   293  // depends on defaultCSS and cockatriceCSS.
   294  func TestBlockchain_GetNatives(t *testing.T) {
   295  	const cockatriceHeight = 3
   296  	bc, acc := chain.NewSingleWithCustomConfig(t, func(cfg *config.Blockchain) {
   297  		cfg.Hardforks = map[string]uint32{
   298  			config.HFAspidochelone.String(): 0,
   299  			config.HFBasilisk.String():      0,
   300  			config.HFCockatrice.String():    cockatriceHeight,
   301  		}
   302  		cfg.P2PSigExtensions = true
   303  	})
   304  	e := neotest.NewExecutor(t, bc, acc, acc)
   305  
   306  	// Check genesis-based native contract states.
   307  	natives := bc.GetNatives()
   308  	require.Equal(t, len(nativenames.All), len(natives))
   309  	for _, cs := range natives {
   310  		csFull := state.Contract{
   311  			ContractBase:  cs.ContractBase,
   312  			UpdateCounter: 0,
   313  		}
   314  		jBytes, err := ojson.Marshal(csFull)
   315  		require.NoError(t, err, cs.Manifest.Name)
   316  		require.Equal(t, defaultCSS[cs.Manifest.Name], string(jBytes), fmt.Errorf("contract %s state mismatch", cs.Manifest.Name))
   317  	}
   318  
   319  	// Check native state after update.
   320  	e.GenerateNewBlocks(t, cockatriceHeight)
   321  	natives = bc.GetNatives()
   322  	require.Equal(t, len(nativenames.All), len(natives))
   323  	for _, cs := range natives {
   324  		csFull := state.Contract{
   325  			ContractBase:  cs.ContractBase,
   326  			UpdateCounter: 0, // Since we're comparing only state.NativeContract part, set the update counter to 0 to match the cockatriceCSS.
   327  		}
   328  		jBytes, err := ojson.Marshal(csFull)
   329  		require.NoError(t, err, cs.Manifest.Name)
   330  		require.Equal(t, cockatriceCSS[cs.Manifest.Name], string(jBytes), fmt.Errorf("contract %s state mismatch", cs.Manifest.Name))
   331  	}
   332  }
   333  
   334  func TestManagement_ContractCache(t *testing.T) {
   335  	c := newManagementClient(t)
   336  	managementInvoker := c.WithSigners(c.Committee)
   337  
   338  	cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.Committee.ScriptHash())
   339  	manifestBytes, err := json.Marshal(cs1.Manifest)
   340  	require.NoError(t, err)
   341  	nefBytes, err := cs1.NEF.Bytes()
   342  	require.NoError(t, err)
   343  
   344  	// Deploy contract, abort the transaction and check that Management cache wasn't persisted
   345  	// for FAULTed tx at the same block.
   346  	w := io.NewBufBinWriter()
   347  	emit.AppCall(w.BinWriter, managementInvoker.Hash, "deploy", callflag.All, nefBytes, manifestBytes)
   348  	emit.Opcodes(w.BinWriter, opcode.ABORT)
   349  	tx1 := managementInvoker.PrepareInvocation(t, w.Bytes(), managementInvoker.Signers)
   350  	tx2 := managementInvoker.PrepareInvoke(t, "getContract", cs1.Hash.BytesBE())
   351  	managementInvoker.AddNewBlock(t, tx1, tx2)
   352  	managementInvoker.CheckFault(t, tx1.Hash(), "ABORT")
   353  	managementInvoker.CheckHalt(t, tx2.Hash(), stackitem.Null{})
   354  
   355  	// Deploy the contract and check that cache was persisted for HALTed transaction at the same block.
   356  	tx1 = managementInvoker.PrepareInvoke(t, "deploy", nefBytes, manifestBytes)
   357  	tx2 = managementInvoker.PrepareInvoke(t, "getContract", cs1.Hash.BytesBE())
   358  	managementInvoker.AddNewBlock(t, tx1, tx2)
   359  	managementInvoker.CheckHalt(t, tx1.Hash())
   360  	aer, err := managementInvoker.Chain.GetAppExecResults(tx2.Hash(), trigger.Application)
   361  	require.NoError(t, err)
   362  	require.Equal(t, vmstate.Halt, aer[0].VMState, aer[0].FaultException)
   363  	require.NotEqual(t, stackitem.Null{}, aer[0].Stack)
   364  }
   365  
   366  func TestManagement_ContractDeploy(t *testing.T) {
   367  	c := newManagementClient(t)
   368  	managementInvoker := c.WithSigners(c.Committee)
   369  
   370  	cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.Committee.ScriptHash())
   371  	manifestBytes, err := json.Marshal(cs1.Manifest)
   372  	require.NoError(t, err)
   373  	nefBytes, err := cs1.NEF.Bytes()
   374  	require.NoError(t, err)
   375  
   376  	t.Run("no NEF", func(t *testing.T) {
   377  		managementInvoker.InvokeFail(t, "no valid NEF provided", "deploy", nil, manifestBytes)
   378  	})
   379  	t.Run("no manifest", func(t *testing.T) {
   380  		managementInvoker.InvokeFail(t, "no valid manifest provided", "deploy", nefBytes, nil)
   381  	})
   382  	t.Run("int for NEF", func(t *testing.T) {
   383  		managementInvoker.InvokeFail(t, "invalid NEF file", "deploy", int64(1), manifestBytes)
   384  	})
   385  	t.Run("zero-length NEF", func(t *testing.T) {
   386  		managementInvoker.InvokeFail(t, "invalid NEF file", "deploy", []byte{}, manifestBytes)
   387  	})
   388  	t.Run("array for NEF", func(t *testing.T) {
   389  		managementInvoker.InvokeFail(t, "invalid NEF file", "deploy", []any{int64(1)}, manifestBytes)
   390  	})
   391  	t.Run("bad script in NEF", func(t *testing.T) {
   392  		nf, err := nef.FileFromBytes(nefBytes) // make a full copy
   393  		require.NoError(t, err)
   394  		nf.Script[0] = 0xff
   395  		nf.CalculateChecksum()
   396  		nefBad, err := nf.Bytes()
   397  		require.NoError(t, err)
   398  		managementInvoker.InvokeFail(t, "invalid NEF file", "deploy", nefBad, manifestBytes)
   399  	})
   400  	t.Run("int for manifest", func(t *testing.T) {
   401  		managementInvoker.InvokeFail(t, "invalid manifest", "deploy", nefBytes, int64(1))
   402  	})
   403  	t.Run("zero-length manifest", func(t *testing.T) {
   404  		managementInvoker.InvokeFail(t, "invalid manifest", "deploy", nefBytes, []byte{})
   405  	})
   406  	t.Run("array for manifest", func(t *testing.T) {
   407  		managementInvoker.InvokeFail(t, "invalid manifest", "deploy", nefBytes, []any{int64(1)})
   408  	})
   409  	t.Run("non-utf8 manifest", func(t *testing.T) {
   410  		manifestBad := bytes.Replace(manifestBytes, []byte("TestMain"), []byte("\xff\xfe\xfd"), 1) // Replace name.
   411  		managementInvoker.InvokeFail(t, "manifest is not UTF-8 compliant", "deploy", nefBytes, manifestBad)
   412  	})
   413  	t.Run("invalid manifest", func(t *testing.T) {
   414  		pkey, err := keys.NewPrivateKey()
   415  		require.NoError(t, err)
   416  
   417  		badManifest := cs1.Manifest
   418  		badManifest.Groups = []manifest.Group{{PublicKey: pkey.PublicKey(), Signature: make([]byte, keys.SignatureLen)}}
   419  		manifB, err := json.Marshal(&badManifest)
   420  		require.NoError(t, err)
   421  
   422  		managementInvoker.InvokeFail(t, "invalid manifest", "deploy", nefBytes, manifB)
   423  	})
   424  	t.Run("bad methods in manifest 1", func(t *testing.T) {
   425  		badManifest := cs1.Manifest
   426  		badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods))
   427  		copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods)
   428  		badManifest.ABI.Methods[0].Offset = 100500 // out of bounds
   429  		manifB, err := json.Marshal(&badManifest)
   430  		require.NoError(t, err)
   431  
   432  		managementInvoker.InvokeFail(t, "method add/2: offset is out of the script range", "deploy", nefBytes, manifB)
   433  	})
   434  	t.Run("bad methods in manifest 2", func(t *testing.T) {
   435  		var badManifest = cs1.Manifest
   436  		badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods))
   437  		copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods)
   438  		badManifest.ABI.Methods[0].Offset = len(cs1.NEF.Script) - 2 // Ends with `CALLT(X,X);RET`.
   439  
   440  		manifB, err := json.Marshal(badManifest)
   441  		require.NoError(t, err)
   442  
   443  		managementInvoker.InvokeFail(t, "some methods point to wrong offsets (not to instruction boundary)", "deploy", nefBytes, manifB)
   444  	})
   445  	t.Run("duplicated methods in manifest 1", func(t *testing.T) {
   446  		badManifest := cs1.Manifest
   447  		badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods))
   448  		copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods)
   449  		badManifest.ABI.Methods[0] = badManifest.ABI.Methods[1] // duplicates
   450  		manifB, err := json.Marshal(&badManifest)
   451  		require.NoError(t, err)
   452  
   453  		managementInvoker.InvokeFail(t, "duplicate method specifications", "deploy", nefBytes, manifB)
   454  	})
   455  	t.Run("duplicated events in manifest 1", func(t *testing.T) {
   456  		badManifest := cs1.Manifest
   457  		badManifest.ABI.Methods = make([]manifest.Method, len(cs1.Manifest.ABI.Methods))
   458  		copy(badManifest.ABI.Methods, cs1.Manifest.ABI.Methods)
   459  		badManifest.ABI.Events = []manifest.Event{{Name: "event"}, {Name: "event"}} // duplicates
   460  		manifB, err := json.Marshal(&badManifest)
   461  		require.NoError(t, err)
   462  
   463  		managementInvoker.InvokeFail(t, "duplicate event names", "deploy", nefBytes, manifB)
   464  	})
   465  
   466  	t.Run("not enough GAS", func(t *testing.T) {
   467  		tx := managementInvoker.NewUnsignedTx(t, managementInvoker.Hash, "deploy", nefBytes, manifestBytes)
   468  		managementInvoker.SignTx(t, tx, 1_0000_0000, managementInvoker.Signers...)
   469  		managementInvoker.AddNewBlock(t, tx)
   470  		managementInvoker.CheckFault(t, tx.Hash(), "gas limit exceeded")
   471  	})
   472  
   473  	si, err := cs1.ToStackItem()
   474  	require.NoError(t, err)
   475  
   476  	t.Run("positive", func(t *testing.T) {
   477  		tx1 := managementInvoker.PrepareInvoke(t, "deploy", nefBytes, manifestBytes)
   478  		tx2 := managementInvoker.PrepareInvoke(t, "getContract", cs1.Hash.BytesBE())
   479  		managementInvoker.AddNewBlock(t, tx1, tx2)
   480  		managementInvoker.CheckHalt(t, tx1.Hash(), si)
   481  		managementInvoker.CheckHalt(t, tx2.Hash(), si)
   482  		managementInvoker.CheckTxNotificationEvent(t, tx1.Hash(), 0, state.NotificationEvent{
   483  			ScriptHash: c.NativeHash(t, nativenames.Management),
   484  			Name:       "Deploy",
   485  			Item:       stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}),
   486  		})
   487  		t.Run("_deploy called", func(t *testing.T) {
   488  			helperInvoker := c.Executor.CommitteeInvoker(cs1.Hash)
   489  			expected := stackitem.NewArray([]stackitem.Item{stackitem.Make("create"), stackitem.Null{}})
   490  			expectedBytes, err := stackitem.Serialize(expected)
   491  			require.NoError(t, err)
   492  			helperInvoker.Invoke(t, stackitem.NewByteArray(expectedBytes), "getValue")
   493  		})
   494  		t.Run("get after deploy", func(t *testing.T) {
   495  			managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE())
   496  		})
   497  		t.Run("hasMethod after deploy", func(t *testing.T) {
   498  			managementInvoker.Invoke(t, stackitem.NewBool(true), "hasMethod", cs1.Hash.BytesBE(), "add", 2)
   499  			managementInvoker.Invoke(t, stackitem.NewBool(false), "hasMethod", cs1.Hash.BytesBE(), "add", 1)
   500  			managementInvoker.Invoke(t, stackitem.NewBool(false), "hasMethod", cs1.Hash.BytesLE(), "add", 2)
   501  		})
   502  		t.Run("get after restore", func(t *testing.T) {
   503  			w := io.NewBufBinWriter()
   504  			require.NoError(t, chaindump.Dump(c.Executor.Chain, w.BinWriter, 0, c.Executor.Chain.BlockHeight()+1))
   505  			require.NoError(t, w.Err)
   506  
   507  			r := io.NewBinReaderFromBuf(w.Bytes())
   508  			bc2, acc := chain.NewSingle(t)
   509  			e2 := neotest.NewExecutor(t, bc2, acc, acc)
   510  			managementInvoker2 := e2.CommitteeInvoker(e2.NativeHash(t, nativenames.Management))
   511  
   512  			require.NoError(t, chaindump.Restore(bc2, r, 0, c.Executor.Chain.BlockHeight()+1, nil))
   513  			require.NoError(t, r.Err)
   514  			managementInvoker2.Invoke(t, si, "getContract", cs1.Hash.BytesBE())
   515  		})
   516  	})
   517  	t.Run("contract already exists", func(t *testing.T) {
   518  		managementInvoker.InvokeFail(t, "contract already exists", "deploy", nefBytes, manifestBytes)
   519  	})
   520  	t.Run("failed _deploy", func(t *testing.T) {
   521  		deployScript := []byte{byte(opcode.ABORT)}
   522  		m := manifest.NewManifest("TestDeployAbort")
   523  		m.ABI.Methods = []manifest.Method{
   524  			{
   525  				Name:   manifest.MethodDeploy,
   526  				Offset: 0,
   527  				Parameters: []manifest.Parameter{
   528  					manifest.NewParameter("data", smartcontract.AnyType),
   529  					manifest.NewParameter("isUpdate", smartcontract.BoolType),
   530  				},
   531  				ReturnType: smartcontract.VoidType,
   532  			},
   533  		}
   534  		nefD, err := nef.NewFile(deployScript)
   535  		require.NoError(t, err)
   536  		nefDb, err := nefD.Bytes()
   537  		require.NoError(t, err)
   538  		manifD, err := json.Marshal(m)
   539  		require.NoError(t, err)
   540  		managementInvoker.InvokeFail(t, "ABORT", "deploy", nefDb, manifD)
   541  
   542  		t.Run("get after failed deploy", func(t *testing.T) {
   543  			h := state.CreateContractHash(c.CommitteeHash, nefD.Checksum, m.Name)
   544  			managementInvoker.Invoke(t, stackitem.Null{}, "getContract", h.BytesBE())
   545  		})
   546  	})
   547  	t.Run("bad _deploy", func(t *testing.T) { // invalid _deploy signature
   548  		deployScript := []byte{byte(opcode.RET)}
   549  		m := manifest.NewManifest("TestBadDeploy")
   550  		m.ABI.Methods = []manifest.Method{
   551  			{
   552  				Name:   manifest.MethodDeploy,
   553  				Offset: 0,
   554  				Parameters: []manifest.Parameter{
   555  					manifest.NewParameter("data", smartcontract.AnyType),
   556  					manifest.NewParameter("isUpdate", smartcontract.BoolType),
   557  				},
   558  				ReturnType: smartcontract.ArrayType,
   559  			},
   560  		}
   561  		nefD, err := nef.NewFile(deployScript)
   562  		require.NoError(t, err)
   563  		nefDb, err := nefD.Bytes()
   564  		require.NoError(t, err)
   565  		manifD, err := json.Marshal(m)
   566  		require.NoError(t, err)
   567  		managementInvoker.InvokeFail(t, "invalid return values count: expected 0, got 2", "deploy", nefDb, manifD)
   568  
   569  		t.Run("get after bad _deploy", func(t *testing.T) {
   570  			h := state.CreateContractHash(c.CommitteeHash, nefD.Checksum, m.Name)
   571  			managementInvoker.Invoke(t, stackitem.Null{}, "getContract", h.BytesBE())
   572  		})
   573  	})
   574  }
   575  
   576  func TestManagement_StartFromHeight(t *testing.T) {
   577  	// Create database to be able to start another chain from the same height later.
   578  	ldbDir := t.TempDir()
   579  	dbConfig := dbconfig.DBConfiguration{
   580  		Type: dbconfig.LevelDB,
   581  		LevelDBOptions: dbconfig.LevelDBOptions{
   582  			DataDirectoryPath: ldbDir,
   583  		},
   584  	}
   585  	newLevelStore, err := storage.NewLevelDBStore(dbConfig.LevelDBOptions)
   586  	require.Nil(t, err, "NewLevelDBStore error")
   587  
   588  	// Create blockchain and put contract state to it.
   589  	bc, acc := chain.NewSingleWithCustomConfigAndStore(t, nil, newLevelStore, false)
   590  	go bc.Run()
   591  	e := neotest.NewExecutor(t, bc, acc, acc)
   592  	c := e.CommitteeInvoker(e.NativeHash(t, nativenames.Management))
   593  	managementInvoker := c.WithSigners(c.Committee)
   594  
   595  	cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.CommitteeHash)
   596  	manifestBytes, err := json.Marshal(cs1.Manifest)
   597  	require.NoError(t, err)
   598  	nefBytes, err := cs1.NEF.Bytes()
   599  	require.NoError(t, err)
   600  
   601  	si, err := cs1.ToStackItem()
   602  	require.NoError(t, err)
   603  
   604  	managementInvoker.Invoke(t, si, "deploy", nefBytes, manifestBytes)
   605  	managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE())
   606  
   607  	// Close current blockchain and start the new one from the same height with the same db.
   608  	bc.Close()
   609  	newLevelStore, err = storage.NewLevelDBStore(dbConfig.LevelDBOptions)
   610  	require.NoError(t, err)
   611  	bc2, acc := chain.NewSingleWithCustomConfigAndStore(t, nil, newLevelStore, true)
   612  	e2 := neotest.NewExecutor(t, bc2, acc, acc)
   613  	managementInvoker2 := e2.CommitteeInvoker(e2.NativeHash(t, nativenames.Management))
   614  
   615  	// Check that initialisation of native Management was correctly performed.
   616  	managementInvoker2.Invoke(t, si, "getContract", cs1.Hash.BytesBE())
   617  }
   618  
   619  func TestManagement_DeployManifestOverflow(t *testing.T) {
   620  	c := newManagementClient(t)
   621  	managementInvoker := c.WithSigners(c.Committee)
   622  
   623  	cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.CommitteeHash)
   624  	manif1, err := json.Marshal(cs1.Manifest)
   625  	require.NoError(t, err)
   626  	nef1, err := nef.NewFile(cs1.NEF.Script)
   627  	require.NoError(t, err)
   628  	nef1b, err := nef1.Bytes()
   629  	require.NoError(t, err)
   630  
   631  	w := io.NewBufBinWriter()
   632  	emit.Bytes(w.BinWriter, manif1)
   633  	emit.Int(w.BinWriter, manifest.MaxManifestSize)
   634  	emit.Opcodes(w.BinWriter, opcode.NEWBUFFER, opcode.CAT)
   635  	emit.Bytes(w.BinWriter, nef1b)
   636  	emit.Int(w.BinWriter, 2)
   637  	emit.Opcodes(w.BinWriter, opcode.PACK)
   638  	emit.AppCallNoArgs(w.BinWriter, managementInvoker.Hash, "deploy", callflag.All)
   639  	require.NoError(t, w.Err)
   640  	script := w.Bytes()
   641  
   642  	tx := transaction.New(script, 0)
   643  	tx.ValidUntilBlock = managementInvoker.Chain.BlockHeight() + 1
   644  	managementInvoker.SignTx(t, tx, 100_0000_0000, managementInvoker.Signers...)
   645  	managementInvoker.AddNewBlock(t, tx)
   646  	managementInvoker.CheckFault(t, tx.Hash(), fmt.Sprintf("invalid manifest: len is %d (max %d)", manifest.MaxManifestSize+len(manif1), manifest.MaxManifestSize))
   647  }
   648  
   649  func TestManagement_ContractDeployAndUpdateWithParameter(t *testing.T) {
   650  	c := newManagementClient(t)
   651  	managementInvoker := c.WithSigners(c.Committee)
   652  
   653  	cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.CommitteeHash)
   654  	cs1.Manifest.Permissions = []manifest.Permission{*manifest.NewPermission(manifest.PermissionWildcard)}
   655  	cs1.ID = 1
   656  	cs1.Hash = state.CreateContractHash(c.CommitteeHash, cs1.NEF.Checksum, cs1.Manifest.Name)
   657  	manif1, err := json.Marshal(cs1.Manifest)
   658  	require.NoError(t, err)
   659  	nef1b, err := cs1.NEF.Bytes()
   660  	require.NoError(t, err)
   661  
   662  	si, err := cs1.ToStackItem()
   663  	require.NoError(t, err)
   664  	managementInvoker.Invoke(t, si, "deploy", nef1b, manif1)
   665  	helperInvoker := c.Executor.CommitteeInvoker(cs1.Hash)
   666  
   667  	t.Run("_deploy called", func(t *testing.T) {
   668  		expected := stackitem.NewArray([]stackitem.Item{stackitem.Make("create"), stackitem.Null{}})
   669  		expectedBytes, err := stackitem.Serialize(expected)
   670  		require.NoError(t, err)
   671  		helperInvoker.Invoke(t, stackitem.NewByteArray(expectedBytes), "getValue")
   672  	})
   673  
   674  	cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.RET))
   675  	cs1.NEF.Checksum = cs1.NEF.CalculateChecksum()
   676  	nef1b, err = cs1.NEF.Bytes()
   677  	require.NoError(t, err)
   678  	cs1.UpdateCounter++
   679  
   680  	helperInvoker.Invoke(t, stackitem.Null{}, "update", nef1b, nil, "new data")
   681  
   682  	t.Run("_deploy called", func(t *testing.T) {
   683  		expected := stackitem.NewArray([]stackitem.Item{stackitem.Make("update"), stackitem.Make("new data")})
   684  		expectedBytes, err := stackitem.Serialize(expected)
   685  		require.NoError(t, err)
   686  		helperInvoker.Invoke(t, stackitem.NewByteArray(expectedBytes), "getValue")
   687  	})
   688  }
   689  
   690  func TestManagement_ContractUpdate(t *testing.T) {
   691  	c := newManagementClient(t)
   692  	managementInvoker := c.WithSigners(c.Committee)
   693  
   694  	cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.CommitteeHash)
   695  	// Allow calling management contract.
   696  	cs1.Manifest.Permissions = []manifest.Permission{*manifest.NewPermission(manifest.PermissionWildcard)}
   697  	manifestBytes, err := json.Marshal(cs1.Manifest)
   698  	require.NoError(t, err)
   699  	nefBytes, err := cs1.NEF.Bytes()
   700  	require.NoError(t, err)
   701  
   702  	si, err := cs1.ToStackItem()
   703  	require.NoError(t, err)
   704  	managementInvoker.Invoke(t, si, "deploy", nefBytes, manifestBytes)
   705  	helperInvoker := c.Executor.CommitteeInvoker(cs1.Hash)
   706  
   707  	t.Run("unknown contract", func(t *testing.T) {
   708  		managementInvoker.InvokeFail(t, "contract doesn't exist", "update", nefBytes, manifestBytes)
   709  	})
   710  	t.Run("zero-length NEF", func(t *testing.T) {
   711  		helperInvoker.InvokeFail(t, "invalid NEF file: empty", "update", []byte{}, manifestBytes)
   712  	})
   713  	t.Run("zero-length manifest", func(t *testing.T) {
   714  		helperInvoker.InvokeFail(t, "invalid manifest: empty", "update", nefBytes, []byte{})
   715  	})
   716  	t.Run("no real params", func(t *testing.T) {
   717  		helperInvoker.InvokeFail(t, "both NEF and manifest are nil", "update", nil, nil)
   718  	})
   719  	t.Run("invalid manifest", func(t *testing.T) {
   720  		pkey, err := keys.NewPrivateKey()
   721  		require.NoError(t, err)
   722  
   723  		var badManifest = cs1.Manifest
   724  		badManifest.Groups = []manifest.Group{{PublicKey: pkey.PublicKey(), Signature: make([]byte, keys.SignatureLen)}}
   725  		manifB, err := json.Marshal(badManifest)
   726  		require.NoError(t, err)
   727  
   728  		helperInvoker.InvokeFail(t, "invalid manifest: incorrect group signature", "update", nefBytes, manifB)
   729  	})
   730  	t.Run("manifest and script mismatch", func(t *testing.T) {
   731  		nf, err := nef.FileFromBytes(nefBytes) // Make a full copy.
   732  		require.NoError(t, err)
   733  		nf.Script = append(nf.Script, byte(opcode.RET))
   734  		copy(nf.Script[1:], nf.Script)  // Now all method offsets are wrong.
   735  		nf.Script[0] = byte(opcode.RET) // Even though the script is correct.
   736  		nf.CalculateChecksum()
   737  		nefnew, err := nf.Bytes()
   738  		require.NoError(t, err)
   739  		helperInvoker.InvokeFail(t, "invalid NEF file: checksum verification failure", "update", nefnew, manifestBytes)
   740  	})
   741  
   742  	t.Run("change name", func(t *testing.T) {
   743  		var badManifest = cs1.Manifest
   744  		badManifest.Name += "tail"
   745  		manifB, err := json.Marshal(badManifest)
   746  		require.NoError(t, err)
   747  
   748  		helperInvoker.InvokeFail(t, "contract name can't be changed", "update", nefBytes, manifB)
   749  	})
   750  
   751  	cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.RET))
   752  	cs1.NEF.Checksum = cs1.NEF.CalculateChecksum()
   753  	nefBytes, err = cs1.NEF.Bytes()
   754  	require.NoError(t, err)
   755  	cs1.UpdateCounter++
   756  	si, err = cs1.ToStackItem()
   757  	require.NoError(t, err)
   758  
   759  	t.Run("update script, positive", func(t *testing.T) {
   760  		tx1 := helperInvoker.PrepareInvoke(t, "update", nefBytes, nil)
   761  		tx2 := managementInvoker.PrepareInvoke(t, "getContract", cs1.Hash.BytesBE())
   762  		managementInvoker.AddNewBlock(t, tx1, tx2)
   763  		managementInvoker.CheckHalt(t, tx1.Hash(), stackitem.Null{})
   764  		managementInvoker.CheckHalt(t, tx2.Hash(), si)
   765  		managementInvoker.CheckTxNotificationEvent(t, tx1.Hash(), 0, state.NotificationEvent{
   766  			ScriptHash: c.NativeHash(t, nativenames.Management),
   767  			Name:       "Update",
   768  			Item:       stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}),
   769  		})
   770  		t.Run("_deploy called", func(t *testing.T) {
   771  			helperInvoker := c.Executor.CommitteeInvoker(cs1.Hash)
   772  			expected := stackitem.NewArray([]stackitem.Item{stackitem.Make("update"), stackitem.Null{}})
   773  			expectedBytes, err := stackitem.Serialize(expected)
   774  			require.NoError(t, err)
   775  			helperInvoker.Invoke(t, stackitem.NewByteArray(expectedBytes), "getValue")
   776  		})
   777  		t.Run("check contract", func(t *testing.T) {
   778  			managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE())
   779  		})
   780  	})
   781  
   782  	cs1.Manifest.Extra = []byte(`"update me"`)
   783  	manifestBytes, err = json.Marshal(cs1.Manifest)
   784  	require.NoError(t, err)
   785  	cs1.UpdateCounter++
   786  	si, err = cs1.ToStackItem()
   787  	require.NoError(t, err)
   788  
   789  	t.Run("update manifest, positive", func(t *testing.T) {
   790  		updHash := helperInvoker.Invoke(t, stackitem.Null{}, "update", nil, manifestBytes)
   791  		helperInvoker.CheckTxNotificationEvent(t, updHash, 0, state.NotificationEvent{
   792  			ScriptHash: helperInvoker.NativeHash(t, nativenames.Management),
   793  			Name:       "Update",
   794  			Item:       stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}),
   795  		})
   796  		t.Run("check contract", func(t *testing.T) {
   797  			managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE())
   798  		})
   799  	})
   800  
   801  	cs1.NEF.Script = append(cs1.NEF.Script, byte(opcode.ABORT))
   802  	cs1.NEF.Checksum = cs1.NEF.CalculateChecksum()
   803  	nefBytes, err = cs1.NEF.Bytes()
   804  	require.NoError(t, err)
   805  	cs1.Manifest.Extra = []byte(`"update me once more"`)
   806  	manifestBytes, err = json.Marshal(cs1.Manifest)
   807  	require.NoError(t, err)
   808  	cs1.UpdateCounter++
   809  	si, err = cs1.ToStackItem()
   810  	require.NoError(t, err)
   811  
   812  	t.Run("update both script and manifest", func(t *testing.T) {
   813  		updHash := helperInvoker.Invoke(t, stackitem.Null{}, "update", nefBytes, manifestBytes)
   814  		helperInvoker.CheckTxNotificationEvent(t, updHash, 0, state.NotificationEvent{
   815  			ScriptHash: helperInvoker.NativeHash(t, nativenames.Management),
   816  			Name:       "Update",
   817  			Item:       stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}),
   818  		})
   819  		t.Run("check contract", func(t *testing.T) {
   820  			managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE())
   821  		})
   822  	})
   823  }
   824  
   825  func TestManagement_GetContract(t *testing.T) {
   826  	c := newManagementClient(t)
   827  	managementInvoker := c.WithSigners(c.Committee)
   828  
   829  	cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.CommitteeHash)
   830  	manifestBytes, err := json.Marshal(cs1.Manifest)
   831  	require.NoError(t, err)
   832  	nefBytes, err := cs1.NEF.Bytes()
   833  	require.NoError(t, err)
   834  
   835  	si, err := cs1.ToStackItem()
   836  	require.NoError(t, err)
   837  	managementInvoker.Invoke(t, si, "deploy", nefBytes, manifestBytes)
   838  
   839  	t.Run("bad parameter type", func(t *testing.T) {
   840  		managementInvoker.InvokeFail(t, "invalid conversion: Array/ByteString", "getContract", []any{int64(1)})
   841  	})
   842  	t.Run("not a hash", func(t *testing.T) {
   843  		managementInvoker.InvokeFail(t, "expected byte size of 20 got 3", "getContract", []byte{1, 2, 3})
   844  	})
   845  	t.Run("positive", func(t *testing.T) {
   846  		managementInvoker.Invoke(t, si, "getContract", cs1.Hash.BytesBE())
   847  	})
   848  	t.Run("by ID, bad parameter type", func(t *testing.T) {
   849  		managementInvoker.InvokeFail(t, "invalid conversion: Array/Integer", "getContractById", []any{int64(1)})
   850  	})
   851  	t.Run("by ID, bad num", func(t *testing.T) {
   852  		managementInvoker.InvokeFail(t, "id is not a correct int32", "getContractById", []byte{1, 2, 3, 4, 5})
   853  	})
   854  	t.Run("by ID, positive", func(t *testing.T) {
   855  		managementInvoker.Invoke(t, si, "getContractById", cs1.ID)
   856  	})
   857  	t.Run("by ID, native", func(t *testing.T) {
   858  		csm := managementInvoker.Executor.Chain.GetContractState(managementInvoker.Hash)
   859  		require.NotNil(t, csm)
   860  		sim, err := csm.ToStackItem()
   861  		require.NoError(t, err)
   862  		managementInvoker.Invoke(t, sim, "getContractById", -1)
   863  	})
   864  	t.Run("by ID, empty", func(t *testing.T) {
   865  		managementInvoker.Invoke(t, stackitem.Null{}, "getContractById", -100)
   866  	})
   867  	t.Run("contract hashes", func(t *testing.T) {
   868  		w := io.NewBufBinWriter()
   869  		emit.AppCall(w.BinWriter, managementInvoker.Hash, "getContractHashes", callflag.All)
   870  		emit.Opcodes(w.BinWriter, opcode.DUP) // Iterator.
   871  		emit.Syscall(w.BinWriter, interopnames.SystemIteratorNext)
   872  		emit.Opcodes(w.BinWriter, opcode.ASSERT) // Has one element.
   873  		emit.Opcodes(w.BinWriter, opcode.DUP)    // Iterator.
   874  		emit.Syscall(w.BinWriter, interopnames.SystemIteratorValue)
   875  		emit.Opcodes(w.BinWriter, opcode.SWAP) // Iterator to the top.
   876  		emit.Syscall(w.BinWriter, interopnames.SystemIteratorNext)
   877  		emit.Opcodes(w.BinWriter, opcode.NOT)
   878  		emit.Opcodes(w.BinWriter, opcode.ASSERT) // No more elements, single value left on the stack.
   879  		require.NoError(t, w.Err)
   880  		h := managementInvoker.InvokeScript(t, w.Bytes(), managementInvoker.Signers)
   881  		managementInvoker.Executor.CheckHalt(t, h, stackitem.NewStruct([]stackitem.Item{stackitem.Make([]byte{0, 0, 0, 1}), stackitem.Make(cs1.Hash.BytesBE())}))
   882  	})
   883  }
   884  
   885  func TestManagement_ContractDestroy(t *testing.T) {
   886  	c := newManagementClient(t)
   887  	managementInvoker := c.WithSigners(c.Committee)
   888  
   889  	cs1, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, c.CommitteeHash)
   890  	// Allow calling management contract.
   891  	cs1.Manifest.Permissions = []manifest.Permission{*manifest.NewPermission(manifest.PermissionWildcard)}
   892  	manifestBytes, err := json.Marshal(cs1.Manifest)
   893  	require.NoError(t, err)
   894  	nefBytes, err := cs1.NEF.Bytes()
   895  	require.NoError(t, err)
   896  
   897  	si, err := cs1.ToStackItem()
   898  	require.NoError(t, err)
   899  	managementInvoker.Invoke(t, si, "deploy", nefBytes, manifestBytes)
   900  	helperInvoker := c.Executor.CommitteeInvoker(cs1.Hash)
   901  
   902  	t.Run("no contract", func(t *testing.T) {
   903  		managementInvoker.InvokeFail(t, "key not found", "destroy")
   904  	})
   905  	t.Run("positive", func(t *testing.T) {
   906  		dstrHash := helperInvoker.Invoke(t, stackitem.Null{}, "destroy")
   907  		helperInvoker.CheckTxNotificationEvent(t, dstrHash, 0, state.NotificationEvent{
   908  			ScriptHash: helperInvoker.NativeHash(t, nativenames.Management),
   909  			Name:       "Destroy",
   910  			Item:       stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray(cs1.Hash.BytesBE())}),
   911  		})
   912  		t.Run("check contract", func(t *testing.T) {
   913  			managementInvoker.Invoke(t, stackitem.Null{}, "getContract", cs1.Hash.BytesBE())
   914  		})
   915  		// deploy after destroy should fail
   916  		managementInvoker.InvokeFail(t, fmt.Sprintf("the contract %s has been blocked", cs1.Hash.StringLE()), "deploy", nefBytes, manifestBytes)
   917  	})
   918  }