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 }